diff --git a/.env b/.env index d5a16be2..3af9ffcb 100644 --- a/.env +++ b/.env @@ -2,9 +2,9 @@ BUILD_IMG_NAME=nokia/kong-oidc INTEGRATION_PATH=test/docker/integration UNIT_PATH=test/docker/unit -KONG_BASE_TAG=:1.0-centos +KONG_BASE_TAG=:2.2.1-centos KONG_TAG= -KONG_DB_TAG=:10.1 +KONG_DB_TAG=:12 KONG_DB_PORT=5432 KONG_DB_USER=kong KONG_DB_PW=kong diff --git a/README.md b/README.md index b8c6ad95..a26c988e 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ ngx.ctx.authenticated_credential = { } ``` +For successfully authenticated request, possible (anonymous) consumer identity set by higher priority plugin is cleared as part of setting the credentials. + The plugin will try to retrieve the user's groups from a field in the token (default `groups`) and set `kong.ctx.shared.authenticated_groups` so that Kong authorization plugins can make decisions based on the user's group membership. ## Dependencies @@ -97,6 +99,12 @@ If you're using `luarocks` execute the following: | `config.disable_id_token_header` | no | false | Disable passing the ID Token to the upstream server | | `config.disable_access_token_header` | no | false | Disable passing the Access Token to the upstream server | | `config.groups_claim` | groups | false | Name of the claim in the token to get groups from | +| `config.skip_already_auth_requests` | no | false | Ignore requests where credentials have already been set by a higher priority plugin such as basic-auth | +| `config.bearer_jwt_auth_enable` | no | false | Authenticate based on JWT (ID) token provided in Authorization (Bearer) header. Checks iss, sub, aud, exp, iat (as in ID token). `config.discovery` must be defined to discover JWKS | +| `config.bearer_jwt_auth_allowed_auds` | | false | List of JWT token `aud` values allowed when validating JWT token in Authorization header. If not provided, uses value from `config.client_id` | +| `config.bearer_jwt_auth_signing_algs` | [ 'RS256' ] | false | List of allowed signing algorithms for Authorization header JWT token validation. Must match to OIDC provider and `resty-openidc` supported algorithms | +| `config.header_names` | | false | List of custom upstream HTTP headers to be added based on claims. Must have same number of elements as `config.header_claims`. Example: `[ 'x-oidc-email', 'x-oidc-email-verified' ]` | +| `config.header_claims` | | false | List of claims to be used as source for custom upstream headers. Claims are sourced from Userinfo, ID Token, Bearer JWT, Introspection, depending on auth method. Use only claims containing simple string values. Example: `[ 'email', 'email_verified'` | ### Enabling kong-oidc @@ -153,6 +161,8 @@ Server: kong/0.11.0 ### Upstream API request +For successfully authenticated request, the plugin will set upstream header `X-Credential-Identifier` to contain `sub` claim from user info, ID token or introspection result. Header `X-Anonymous-Consumer` is cleared. + The plugin adds a additional `X-Userinfo`, `X-Access-Token` and `X-Id-Token` headers to the upstream request, which can be consumer by upstream server. All of them are base64 encoded: ```http diff --git a/kong-oidc-1.2.1-1.rockspec b/kong-oidc-1.2.1-1.rockspec index 5706880d..6e05cd56 100644 --- a/kong-oidc-1.2.1-1.rockspec +++ b/kong-oidc-1.2.1-1.rockspec @@ -22,7 +22,7 @@ description = { license = "Apache 2.0" } dependencies = { - "lua-resty-openidc ~> 1.7.2-1" + "lua-resty-openidc ~> 1.7.4-1" } build = { type = "builtin", diff --git a/kong/plugins/oidc/handler.lua b/kong/plugins/oidc/handler.lua index 207e0726..2b2e652b 100644 --- a/kong/plugins/oidc/handler.lua +++ b/kong/plugins/oidc/handler.lua @@ -15,6 +15,14 @@ function OidcHandler:access(config) OidcHandler.super.access(self) local oidcConfig = utils.get_options(config, ngx) + -- partial support for plugin chaining: allow skipping requests, where higher priority + -- plugin has already set the credentials. The 'config.anomyous' approach to define + -- "and/or" relationship between auth plugins is not utilized + if oidcConfig.skip_already_auth_requests and kong.client.get_credential() then + ngx.log(ngx.DEBUG, "OidcHandler ignoring already auth request: " .. ngx.var.request_uri) + return + end + if filter.shouldProcessRequest(oidcConfig) then session.configure(config) handle(oidcConfig) @@ -27,21 +35,48 @@ end function handle(oidcConfig) local response + + if oidcConfig.bearer_jwt_auth_enable then + response = verify_bearer_jwt(oidcConfig) + if response then + utils.setCredentials(response) + utils.injectGroups(response, oidcConfig.groups_claim) + utils.injectHeaders(oidcConfig.header_names, oidcConfig.header_claims, { response }) + if not oidcConfig.disable_userinfo_header then + utils.injectUser(response, oidcConfig.userinfo_header_name) + end + return + end + end + if oidcConfig.introspection_endpoint then response = introspect(oidcConfig) if response then - utils.injectUser(response, oidcConfig.userinfo_header_name) + utils.setCredentials(response) utils.injectGroups(response, oidcConfig.groups_claim) + utils.injectHeaders(oidcConfig.header_names, oidcConfig.header_claims, { response }) + if not oidcConfig.disable_userinfo_header then + utils.injectUser(response, oidcConfig.userinfo_header_name) + end end end if response == nil then response = make_oidc(oidcConfig) if response then + if response.user or response.id_token then + -- is there any scenario where lua-resty-openidc would not provide id_token? + utils.setCredentials(response.user or response.id_token) + end + if response.user and response.user[oidcConfig.groups_claim] ~= nil then + utils.injectGroups(response.user, oidcConfig.groups_claim) + elseif response.id_token then + utils.injectGroups(response.id_token, oidcConfig.groups_claim) + end + utils.injectHeaders(oidcConfig.header_names, oidcConfig.header_claims, { response.user, response.id_token }) if (not oidcConfig.disable_userinfo_header and response.user) then utils.injectUser(response.user, oidcConfig.userinfo_header_name) - utils.injectGroups(response.user, oidcConfig.groups_claim) end if (not oidcConfig.disable_access_token_header and response.access_token) then @@ -94,4 +129,48 @@ function introspect(oidcConfig) return nil end +function verify_bearer_jwt(oidcConfig) + if not utils.has_bearer_access_token() then + return nil + end + -- setup controlled configuration for bearer_jwt_verify + local opts = { + accept_none_alg = false, + accept_unsupported_alg = false, + token_signing_alg_values_expected = oidcConfig.bearer_jwt_auth_signing_algs, + discovery = oidcConfig.discovery, + timeout = oidcConfig.timeout, + ssl_verify = oidcConfig.ssl_verify + } + + local discovery_doc, err = require("resty.openidc").get_discovery_doc(opts) + if err then + kong.log.err('Discovery document retrieval for Bearer JWT verify failed') + return nil + end + + local allowed_auds = oidcConfig.bearer_jwt_auth_allowed_auds or oidcConfig.client_id + + local jwt_validators = require "resty.jwt-validators" + jwt_validators.set_system_leeway(120) + local claim_spec = { + -- mandatory for id token: iss, sub, aud, exp, iat + iss = jwt_validators.equals(discovery_doc.issuer), + sub = jwt_validators.required(), + aud = function(val) return utils.has_common_item(val, allowed_auds) end, + exp = jwt_validators.is_not_expired(), + iat = jwt_validators.required(), + -- optional validations + nbf = jwt_validators.opt_is_not_before(), + } + + local json, err, token = require("resty.openidc").bearer_jwt_verify(opts, claim_spec) + if err then + kong.log.err('Bearer JWT verify failed: ' .. err) + return nil + end + + return json +end + return OidcHandler diff --git a/kong/plugins/oidc/schema.lua b/kong/plugins/oidc/schema.lua index f1cfe955..7b5e58bd 100644 --- a/kong/plugins/oidc/schema.lua +++ b/kong/plugins/oidc/schema.lua @@ -29,6 +29,12 @@ return { disable_id_token_header = { type = "string", required = false, default = "no" }, disable_access_token_header = { type = "string", required = false, default = "no" }, revoke_tokens_on_logout = { type = "string", required = false, default = "no" }, - groups_claim = { type = "string", required = false, default = "groups" } + groups_claim = { type = "string", required = false, default = "groups" }, + skip_already_auth_requests = { type = "string", required = false, default = "no" }, + bearer_jwt_auth_enable = { type = "string", required = false, default = "no" }, + bearer_jwt_auth_allowed_auds = { type = "array", required = false }, + bearer_jwt_auth_signing_algs = { type = "array", required = true, default = { "RS256" } }, + header_names = { type = "array", required = true, default = {} }, + header_claims = { type = "array", required = true, default = {} }, } } diff --git a/kong/plugins/oidc/utils.lua b/kong/plugins/oidc/utils.lua index 7ec3cca8..c531fc5b 100644 --- a/kong/plugins/oidc/utils.lua +++ b/kong/plugins/oidc/utils.lua @@ -1,4 +1,5 @@ local cjson = require("cjson") +local constants = require "kong.constants" local M = {} @@ -70,7 +71,13 @@ function M.get_options(config, ngx) disable_userinfo_header = config.disable_userinfo_header == "yes", disable_id_token_header = config.disable_id_token_header == "yes", disable_access_token_header = config.disable_access_token_header == "yes", - groups_claim = config.groups_claim == "groups" + groups_claim = config.groups_claim, + skip_already_auth_requests = config.skip_already_auth_requests == "yes", + bearer_jwt_auth_enable = config.bearer_jwt_auth_enable == "yes", + bearer_jwt_auth_allowed_auds = config.bearer_jwt_auth_allowed_auds, + bearer_jwt_auth_signing_algs = config.bearer_jwt_auth_signing_algs, + header_names = config.header_names or {}, + header_claims = config.header_claims or {} } end @@ -80,6 +87,51 @@ function M.exit(httpStatusCode, message, ngxCode) ngx.exit(ngxCode) end + +-- Function set_consumer is derived from the following kong auth plugins: +-- https://github.com/Kong/kong/blob/2.2.0/kong/plugins/ldap-auth/access.lua +-- https://github.com/Kong/kong/blob/2.2.0/kong/plugins/oauth2/access.lua +-- Copyright 2016-2020 Kong Inc. Licensed under the Apache License, Version 2.0 +-- https://github.com/Kong/kong/blob/2.2.0/LICENSE +local function set_consumer(consumer, credential) + kong.client.authenticate(consumer, credential) + + 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 + + if credential and credential.sub then + set_header(constants.HEADERS.CREDENTIAL_IDENTIFIER, credential.sub) + else + clear_header(constants.HEADERS.CREDENTIAL_IDENTIFIER) + end + + clear_header(constants.HEADERS.CREDENTIAL_USERNAME) + + if credential then + clear_header(constants.HEADERS.ANONYMOUS) + else + set_header(constants.HEADERS.ANONYMOUS, true) + end +end + function M.injectAccessToken(accessToken, headerName, bearerToken) ngx.log(ngx.DEBUG, "Injecting " .. headerName) local token = accessToken @@ -95,12 +147,15 @@ function M.injectIDToken(idToken, headerName) ngx.req.set_header(headerName, ngx.encode_base64(tokenStr)) end -function M.injectUser(user, headerName) - ngx.log(ngx.DEBUG, "Injecting " .. headerName) +function M.setCredentials(user) local tmp_user = user tmp_user.id = user.sub tmp_user.username = user.preferred_username - ngx.ctx.authenticated_credential = tmp_user + set_consumer(nil, tmp_user) +end + +function M.injectUser(user, headerName) + ngx.log(ngx.DEBUG, "Injecting " .. headerName) local userinfo = cjson.encode(user) ngx.req.set_header(headerName, ngx.encode_base64(userinfo)) end @@ -111,6 +166,27 @@ function M.injectGroups(user, claim) end end +function M.injectHeaders(header_names, header_claims, sources) + if #header_names ~= #header_claims then + kong.log.err('Different number of elements provided in header_names and header_claims. Headers will not be added.') + return + end + for i = 1, #header_names do + local header, claim + header = header_names[i] + claim = header_claims[i] + kong.service.request.clear_header(header) + for j = 1, #sources do + local source + source = sources[j] + if (source and source[claim]) then + kong.service.request.set_header(header, source[claim]) + break + end + end + end +end + function M.has_bearer_access_token() local header = ngx.req.get_headers()['Authorization'] if header and header:find(" ") then @@ -122,4 +198,27 @@ function M.has_bearer_access_token() return false end +-- verify if tables t1 and t2 have at least one common string item +-- instead of table, also string can be provided as t1 or t2 +function M.has_common_item(t1, t2) + if t1 == nil or t2 == nil then + return false + end + if type(t1) == "string" then + t1 = { t1 } + end + if type(t2) == "string" then + t2 = { t2 } + end + local i1, i2 + for _, i1 in pairs(t1) do + for _, i2 in pairs(t2) do + if type(i1) == "string" and type(i2) == "string" and i1 == i2 then + return true + end + end + end + return false +end + return M diff --git a/test/docker/integration/Dockerfile b/test/docker/integration/Dockerfile index 1c65a096..48d721c2 100644 --- a/test/docker/integration/Dockerfile +++ b/test/docker/integration/Dockerfile @@ -1,5 +1,6 @@ ARG KONG_BASE_TAG FROM kong${KONG_BASE_TAG} +USER root ENV LUA_PATH /usr/local/share/lua/5.1/?.lua;/usr/local/kong-oidc/?.lua;; # For lua-cjson @@ -12,6 +13,6 @@ RUN luarocks install luaunit RUN luarocks install lua-cjson # Change openidc version when version in rockspec changes -RUN luarocks install lua-resty-openidc 1.7.2-1 +RUN luarocks install lua-resty-openidc 1.7.4-1 COPY . /usr/local/kong-oidc diff --git a/test/docker/unit/Dockerfile b/test/docker/unit/Dockerfile index 75729b6e..2bacadaf 100644 --- a/test/docker/unit/Dockerfile +++ b/test/docker/unit/Dockerfile @@ -1,6 +1,6 @@ ARG KONG_BASE_TAG FROM kong${KONG_BASE_TAG} - +USER root ENV LUA_PATH /usr/local/share/lua/5.1/?.lua;/usr/local/kong-oidc/?.lua # For lua-cjson ENV LUA_CPATH /usr/local/lib/lua/5.1/?.so @@ -8,7 +8,9 @@ ENV LUA_CPATH /usr/local/lib/lua/5.1/?.so # Install unzip for luarocks, gcc for lua-cjson RUN echo "ip_resolve=4" >> /etc/yum.conf && yum install -y unzip gcc # Change openidc version when version in rockspec changes -RUN luarocks install lua-resty-openidc 1.7.2-1 +RUN luarocks install lua-resty-openidc 1.7.4-1 +RUN luarocks install luacov +RUN luarocks install luaunit WORKDIR /usr/local/kong-oidc diff --git a/test/unit/mockable_case.lua b/test/unit/mockable_case.lua index 66aa367c..ebc90699 100644 --- a/test/unit/mockable_case.lua +++ b/test/unit/mockable_case.lua @@ -31,6 +31,29 @@ function MockableCase:setUp() self.ngx = _G.ngx _G.ngx = self.mocked_ngx + self.mocked_kong = { + client = { + authenticate = function(consumer, credential) + ngx.ctx.authenticated_consumer = consumer + ngx.ctx.authenticated_credential = credential + end + }, + service = { + request = { + clear_header = function(...) end, + set_header = function(...) end + } + }, + log = { + err = function(...) end + }, + ctx = { + shared = {} + } + } + self.kong = _G.kong + _G.kong = self.mocked_kong + self.resty = package.loaded.resty package.loaded["resty.http"] = nil package.preload["resty.http"] = function() @@ -50,6 +73,7 @@ end function MockableCase:tearDown() MockableCase.super:tearDown() _G.ngx = self.ngx + _G.kong = self.kong package.loaded.resty = self.resty package.loaded.cjson = self.cjson end diff --git a/test/unit/run.sh b/test/unit/run.sh index a54ebf63..dc803181 100755 --- a/test/unit/run.sh +++ b/test/unit/run.sh @@ -1,9 +1,13 @@ #!/bin/bash set -e +rm -f luacov.stats.out + # Run all test_*.lua files in test/unit for f in test/unit/test_*.lua; do (set -x lua -lluacov ${f} -o TAP --failure ) -done \ No newline at end of file +done +luacov +cat luacov.report.out diff --git a/test/unit/test_already_auth.lua b/test/unit/test_already_auth.lua new file mode 100644 index 00000000..86403dd4 --- /dev/null +++ b/test/unit/test_already_auth.lua @@ -0,0 +1,44 @@ +local lu = require("luaunit") +TestHandler = require("test.unit.mockable_case"):extend() + + +function TestHandler:setUp() + TestHandler.super:setUp() + + package.loaded["resty.openidc"] = nil + self.module_resty = { openidc = {} } + package.preload["resty.openidc"] = function() + return self.module_resty.openidc + end + + self.handler = require("kong.plugins.oidc.handler")() +end + +function TestHandler:tearDown() + TestHandler.super:tearDown() +end + +function TestHandler:test_skip_already_auth_has_cred() + kong.client.get_credential = function() return { consumer_id = "user" } end + local called_authenticate + self.module_resty.openidc.authenticate = function(opts) + called_authenticate = true + return nil, "error" + end + self.handler:access({ skip_already_auth_requests = "yes" }) + lu.assertNil(called_authenticate) +end + +function TestHandler:test_skip_already_auth_has_no_cred() + kong.client.get_credential = function() return nil end + local called_authenticate + self.module_resty.openidc.authenticate = function(opts) + called_authenticate = true + return nil, "error" + end + self.handler:access({ skip_already_auth_requests = "yes" }) + lu.assertTrue(called_authenticate) +end + + +lu.run() diff --git a/test/unit/test_bearer_jwt_auth.lua b/test/unit/test_bearer_jwt_auth.lua new file mode 100644 index 00000000..edd7a37c --- /dev/null +++ b/test/unit/test_bearer_jwt_auth.lua @@ -0,0 +1,68 @@ +local lu = require("luaunit") +TestHandler = require("test.unit.mockable_case"):extend() + + +function TestHandler:setUp() + TestHandler.super:setUp() + + package.loaded["resty.openidc"] = nil + self.module_resty = { openidc = {} } + package.preload["resty.openidc"] = function() + return self.module_resty.openidc + end + + self.handler = require("kong.plugins.oidc.handler")() +end + +function TestHandler:tearDown() + TestHandler.super:tearDown() +end + +function TestHandler:test_bearer_jwt_auth_success() + ngx.req.get_headers = function() return {Authorization = "Bearer xxx"} end + ngx.encode_base64 = function(x) return "eyJzdWIiOiJzdWIifQ==" end + + self.module_resty.openidc.get_discovery_doc = function(opts) + return { issuer = "https://oidc" } + end + + self.module_resty.openidc.bearer_jwt_verify = function(opts) + token = { + iss = "https://oidc", + sub = "sub111", + aud = "aud222", + groups = { "users" } + } + return token, nil, "xxx" + end + + self.handler:access({ + bearer_jwt_auth_enable = "yes", + client_id = "aud222", + groups_claim = "groups", + userinfo_header_name = "x-userinfo" + }) + lu.assertEquals(ngx.ctx.authenticated_credential.id, "sub111") + lu.assertEquals(kong.ctx.shared.authenticated_groups, { "users" }) +end + +function TestHandler:test_bearer_jwt_auth_fail() + ngx.req.get_headers = function() return {Authorization = "Bearer xxx"} end + local called_authenticate + self.module_resty.openidc.get_discovery_doc = function(opts) + return { issuer = "https://oidc" } + end + + self.module_resty.openidc.bearer_jwt_verify = function(opts) + return nil, "JWT expired" + end + + self.module_resty.openidc.authenticate = function(opts) + called_authenticate = true + return nil, "error" + end + self.handler:access({bearer_jwt_auth_enable = "yes", client_id = "aud222"}) + lu.assertTrue(called_authenticate) +end + +lu.run() diff --git a/test/unit/test_handler_mocking_openidc.lua b/test/unit/test_handler_mocking_openidc.lua index 74a10d55..e988b746 100644 --- a/test/unit/test_handler_mocking_openidc.lua +++ b/test/unit/test_handler_mocking_openidc.lua @@ -22,10 +22,10 @@ end function TestHandler:test_authenticate_ok_no_userinfo() self.module_resty.openidc.authenticate = function(opts) - return {}, false + return { id_token = { sub = "sub"}}, false end - self.handler:access({}) + self.handler:access({disable_id_token_header = "yes"}) lu.assertTrue(self:log_contains("calling authenticate")) end @@ -50,7 +50,7 @@ end function TestHandler:test_authenticate_ok_with_no_accesstoken() self.module_resty.openidc.authenticate = function(opts) - return {}, true + return {id_token = {sub = "sub"}}, true end local headers = {} @@ -58,14 +58,14 @@ function TestHandler:test_authenticate_ok_with_no_accesstoken() headers[h] = v end - self.handler:access({}) + self.handler:access({disable_id_token_header = "yes"}) lu.assertTrue(self:log_contains("calling authenticate")) lu.assertNil(headers['X-Access-Token']) end function TestHandler:test_authenticate_ok_with_accesstoken() self.module_resty.openidc.authenticate = function(opts) - return {access_token = "ACCESS_TOKEN"}, true + return {id_token = { sub = "sub" } , access_token = "ACCESS_TOKEN"}, true end local headers = {} @@ -73,7 +73,7 @@ function TestHandler:test_authenticate_ok_with_accesstoken() headers[h] = v end - self.handler:access({access_token_header_name = 'X-Access-Token'}) + self.handler:access({access_token_header_name = 'X-Access-Token', disable_id_token_header = "yes"}) lu.assertTrue(self:log_contains("calling authenticate")) lu.assertEquals(headers['X-Access-Token'], "ACCESS_TOKEN") end @@ -114,7 +114,7 @@ end function TestHandler:test_authenticate_nok_no_recovery() self.module_resty.openidc.authenticate = function(opts) - return {}, true + return nil, true end self.handler:access({}) @@ -124,7 +124,7 @@ end function TestHandler:test_authenticate_nok_deny() self.module_resty.openidc.authenticate = function(opts) if opts.unauth_action == "deny" then - return {}, "unauthorized request" + return nil, "unauthorized request" end return {}, true end @@ -135,7 +135,7 @@ end function TestHandler:test_authenticate_nok_with_recovery() self.module_resty.openidc.authenticate = function(opts) - return {}, true + return nil, true end self.handler:access({recovery_page_path = "x"}) diff --git a/test/unit/test_header_claims.lua b/test/unit/test_header_claims.lua new file mode 100644 index 00000000..d7f03eca --- /dev/null +++ b/test/unit/test_header_claims.lua @@ -0,0 +1,34 @@ +local lu = require("luaunit") +TestHandler = require("test.unit.mockable_case"):extend() + +function TestHandler:setUp() + TestHandler.super:setUp() + + package.loaded["resty.openidc"] = nil + self.module_resty = { openidc = {} } + package.preload["resty.openidc"] = function() + return self.module_resty.openidc + end + + self.handler = require("kong.plugins.oidc.handler")() +end + +function TestHandler:tearDown() + TestHandler.super:tearDown() +end + +function TestHandler:test_header_add() + self.module_resty.openidc.authenticate = function(opts) + return { user = {sub = "sub", email = "ghost@localhost"}, id_token = { sub = "sub", aud = "aud123"} }, false + end + local headers + headers = {} + kong.service.request.set_header = function(name, value) headers[name] = value end + + self.handler:access({ disable_id_token_header = "yes", disable_userinfo_header = "yes", + header_names = { "X-Email", "X-Aud"}, header_claims = { "email", "aud" } }) + lu.assertEquals(headers["X-Email"], "ghost@localhost") + lu.assertEquals(headers["X-Aud"], "aud123") +end + +lu.run() diff --git a/test/unit/test_introspect.lua b/test/unit/test_introspect.lua index 53b7a7b0..31949334 100644 --- a/test/unit/test_introspect.lua +++ b/test/unit/test_introspect.lua @@ -13,10 +13,15 @@ function TestIntrospect:tearDown() end function TestIntrospect:test_access_token_exists() + package.loaded["resty.openidc"] = nil + self.module_resty = { + openidc = { + introspect = function(...) return { sub = "sub" }, nil end, + } + } + package.preload["resty.openidc"] = function() return self.module_resty.openidc end + ngx.req.get_headers = function() return {Authorization = "Bearer xxx"} end - local dict = {} - function dict:get(key) return key end - _G.ngx.shared = {introspection = dict } ngx.encode_base64 = function(x) return "eyJzdWIiOiJzdWIifQ==" @@ -33,7 +38,14 @@ function TestIntrospect:test_access_token_exists() end function TestIntrospect:test_no_authorization_header() - package.loaded["resty.openidc"].authenticate = function(...) return {}, nil end + package.loaded["resty.openidc"] = nil + self.module_resty = { + openidc = { + authenticate = function(...) return {}, nil end + } + } + package.preload["resty.openidc"] = function() return self.module_resty.openidc end + ngx.req.get_headers = function() return {} end local headers = {} diff --git a/test/unit/test_utils.lua b/test/unit/test_utils.lua index 095ae42e..469acc08 100644 --- a/test/unit/test_utils.lua +++ b/test/unit/test_utils.lua @@ -77,5 +77,16 @@ function TestUtils:testOptions() end +function TestUtils:testCommonItem() + lu.assertFalse(utils.has_common_item(nil, "aud1")) + lu.assertTrue(utils.has_common_item("aud1", "aud1")) + lu.assertFalse(utils.has_common_item("aud1", "aud2")) + lu.assertFalse(utils.has_common_item({"aud1", "aud2"}, "aud3")) + lu.assertTrue(utils.has_common_item({"aud1", "aud2"}, "aud2")) + lu.assertFalse(utils.has_common_item("aud1", {"aud2", "aud3"})) + lu.assertTrue(utils.has_common_item("aud2", {"aud2", "aud3"})) + lu.assertTrue(utils.has_common_item({"aud2","aud3","aud4"}, {"aud4", "aud5"})) + lu.assertFalse(utils.has_common_item({"aud2","aud3","aud4"}, {"aud5", "aud6"})) +end lu.run()