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

Reply via email to