This is an automated email from the ASF dual-hosted git repository.
spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 1cb4dcd26 feat(openid-connect): expose unauth_action parameter in
lua-resty-openidc (#8148)
1cb4dcd26 is described below
commit 1cb4dcd26a7cda6df3673d480cc67dca99dc1748
Author: Jørgen Nystad <[email protected]>
AuthorDate: Tue Jan 10 07:04:19 2023 +0100
feat(openid-connect): expose unauth_action parameter in lua-resty-openidc
(#8148)
---
apisix/plugins/openid-connect.lua | 21 +++-
docs/en/latest/plugins/openid-connect.md | 1 +
t/plugin/openid-connect.t | 2 +-
t/plugin/openid-connect2.t | 187 +++++++++++++++++++++++++++++++
4 files changed, 209 insertions(+), 2 deletions(-)
diff --git a/apisix/plugins/openid-connect.lua
b/apisix/plugins/openid-connect.lua
index 163707f1d..5058eba47 100644
--- a/apisix/plugins/openid-connect.lua
+++ b/apisix/plugins/openid-connect.lua
@@ -86,6 +86,14 @@ local schema = {
type = "string",
description = "the URI will be redirect when request logout_path",
},
+ unauth_action = {
+ type = "string",
+ default = "auth",
+ enum = {"auth", "deny", "pass"},
+ description = "The action performed when client is not authorized.
Use auth to " ..
+ "redirect user to identity provider, deny to respond with 401
Unauthorized, and " ..
+ "pass to allow the request regardless."
+ },
public_key = {type = "string"},
token_signing_alg_values_expected = {type = "string"},
use_pkce = {
@@ -328,15 +336,26 @@ function _M.rewrite(plugin_conf, ctx)
-- Either token validation via introspection endpoint or public key is
-- not configured, and/or token could not be extracted from the
request.
+ local unauth_action = conf.unauth_action
+ if unauth_action ~= "auth" then
+ unauth_action = "deny"
+ end
+
-- Authenticate the request. This will validate the access token if it
-- is stored in a session cookie, and also renew the token if required.
-- If no token can be extracted, the response will redirect to the ID
-- provider's authorization endpoint to initiate the Relying Party
flow.
-- This code path also handles when the ID provider then redirects to
-- the configured redirect URI after successful authentication.
- response, err, _, session = openidc.authenticate(conf, nil, nil,
conf.session)
+ response, err, _, session = openidc.authenticate(conf, nil,
unauth_action, conf.session)
if err then
+ if err == "unauthorized request" then
+ if conf.unauth_action == "pass" then
+ return nil
+ end
+ return 401
+ end
core.log.error("OIDC authentication failed: ", err)
return 500
end
diff --git a/docs/en/latest/plugins/openid-connect.md
b/docs/en/latest/plugins/openid-connect.md
index e44e0f622..a41e02804 100644
--- a/docs/en/latest/plugins/openid-connect.md
+++ b/docs/en/latest/plugins/openid-connect.md
@@ -60,6 +60,7 @@ description: OpenID Connect allows the client to obtain user
information from th
| set_refresh_token_header | boolean | False | false
| | When set to true and a refresh token object is available,
sets it in the `X-Refresh-Token` request header. |
| session | object | False |
| | When bearer_only is set to false, openid-connect will use
Authorization Code flow to authenticate on the IDP, so you need to set the
session-related configuration. |
| session.secret | string | True | Automatic
generation | 16 or more characters | The key used for session encrypt and HMAC
operation. |
+| unauth_action | string | False | "auth"
| | Specify the response type on unauthenticated requests.
"auth" redirects to identity provider, "deny" results in a 401 response, "pass"
will allow the request without authentication. |
NOTE: `encrypt_fields = {"client_secret"}` is also defined in the schema,
which means that the field will be stored encrypted in etcd. See [encrypted
storage fields](../plugin-develop.md#encrypted-storage-fields).
diff --git a/t/plugin/openid-connect.t b/t/plugin/openid-connect.t
index 23dc8ea5b..6f6f7aa0d 100644
--- a/t/plugin/openid-connect.t
+++ b/t/plugin/openid-connect.t
@@ -876,7 +876,7 @@ OIDC introspection failed: invalid token
}
}
--- response_body
-{"access_token_in_authorization_header":false,"bearer_only":false,"client_id":"kbyuFDidLLm280LIwVFiazOqjO3ty8KH","client_secret":"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa","discovery":"http://127.0.0.1:1980/.well-known/openid-configuration","introspection_endpoint_auth_method":"client_secret_basic","logout_path":"/logout","realm":"apisix","scope":"openid","set_access_token_header":true,"set_id_token_header":true,"set_refresh_token_header":false,"set_userinfo_heade
[...]
+{"access_token_in_authorization_header":false,"bearer_only":false,"client_id":"kbyuFDidLLm280LIwVFiazOqjO3ty8KH","client_secret":"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa","discovery":"http://127.0.0.1:1980/.well-known/openid-configuration","introspection_endpoint_auth_method":"client_secret_basic","logout_path":"/logout","realm":"apisix","scope":"openid","set_access_token_header":true,"set_id_token_header":true,"set_refresh_token_header":false,"set_userinfo_heade
[...]
diff --git a/t/plugin/openid-connect2.t b/t/plugin/openid-connect2.t
index c9c963319..f12001b3a 100644
--- a/t/plugin/openid-connect2.t
+++ b/t/plugin/openid-connect2.t
@@ -147,3 +147,190 @@ apisix:
--- response_body
60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa
xMlerg8pE2lPSDlQdPi+MsAwBnzqpyLRar3lUhP2Tdc2oXnWmit92p8cannhDYkBPc6P/Hlx0wSA0T2wle9QyHaW2oqw3bXDQSWWk8Vqq0o=
+
+
+
+=== TEST 3: Set up route with plugin matching URI `/hello` with unauth_action
= "auth".
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "openid-connect": {
+ "client_id":
"kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
+ "client_secret":
"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa",
+ "discovery":
"http://127.0.0.1:1980/.well-known/openid-configuration",
+ "redirect_uri": "https://iresty.com",
+ "ssl_verify": false,
+ "timeout": 10,
+ "scope": "apisix",
+ "unauth_action": "auth",
+ "use_pkce": false
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 4: Access route w/o bearer token. Should redirect to authentication
endpoint of ID provider.
+--- config
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+ local httpc = http.new()
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
+ local res, err = httpc:request_uri(uri, {method = "GET"})
+ ngx.status = res.status
+ local location = res.headers['Location']
+ if location and string.find(location,
'https://samples.auth0.com/authorize') ~= -1 and
+ string.find(location, 'scope=apisix') ~= -1 and
+ string.find(location,
'client_id=kbyuFDidLLm280LIwVFiazOqjO3ty8KH') ~= -1 and
+ string.find(location, 'response_type=code') ~= -1 and
+ string.find(location, 'redirect_uri=https://iresty.com') ~= -1
then
+ ngx.say(true)
+ end
+ }
+ }
+--- timeout: 10s
+--- response_body
+true
+--- error_code: 302
+
+
+
+=== TEST 5: Set up route with plugin matching URI `/hello` with unauth_action
= "deny".
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "openid-connect": {
+ "client_id":
"kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
+ "client_secret":
"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa",
+ "discovery":
"http://127.0.0.1:1980/.well-known/openid-configuration",
+ "redirect_uri": "https://iresty.com",
+ "ssl_verify": false,
+ "timeout": 10,
+ "scope": "apisix",
+ "unauth_action": "deny",
+ "use_pkce": false
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 6: Access route w/o bearer token. Should return unauthorized.
+--- config
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+ local httpc = http.new()
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
+ local res, err = httpc:request_uri(uri, {method = "GET"})
+ ngx.status = res.status
+ ngx.say(true)
+ }
+ }
+--- timeout: 10s
+--- response_body
+true
+--- error_code: 401
+
+
+
+=== TEST 7: Set up route with plugin matching URI `/hello` with unauth_action
= "pass".
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "openid-connect": {
+ "client_id":
"kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
+ "client_secret":
"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa",
+ "discovery":
"http://127.0.0.1:1980/.well-known/openid-configuration",
+ "redirect_uri": "https://iresty.com",
+ "ssl_verify": false,
+ "timeout": 10,
+ "scope": "apisix",
+ "unauth_action": "pass",
+ "use_pkce": false
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 8: Access route w/o bearer token. Should return ok.
+--- config
+ location /t {
+ content_by_lua_block {
+ local http = require "resty.http"
+ local httpc = http.new()
+ local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
+ local res, err = httpc:request_uri(uri, {method = "GET"})
+ if res.status == 200 then
+ ngx.say(true)
+ end
+ }
+ }
+--- timeout: 10s
+--- response_body
+true