fix(openid-connect): the default 'redirect_uri' (#2426) (#7690)
Co-authored-by: Traky Deng <trakydeng@gmail.com>
Co-authored-by: lyy <2424809934@qq.com>
diff --git a/apisix/plugins/openid-connect.lua b/apisix/plugins/openid-connect.lua
index dc0c53d..8ed6ab4 100644
--- a/apisix/plugins/openid-connect.lua
+++ b/apisix/plugins/openid-connect.lua
@@ -86,7 +86,7 @@
},
redirect_uri = {
type = "string",
- description = "use ngx.var.request_uri if not configured"
+ description = "auto append '.apisix/redirect' to ngx.var.uri if not configured"
},
post_logout_redirect_uri = {
type = "string",
@@ -441,7 +441,22 @@
end
if not conf.redirect_uri then
- conf.redirect_uri = ctx.var.request_uri
+ -- NOTE: 'lua-resty-openidc' requires that 'redirect_uri' be
+ -- different from 'uri'. So default to append the
+ -- '.apisix/redirect' suffix if not configured.
+ local suffix = "/.apisix/redirect"
+ local uri = ctx.var.uri
+ if core.string.has_suffix(uri, suffix) then
+ -- This is the redirection response from the OIDC provider.
+ conf.redirect_uri = uri
+ else
+ if string.sub(uri, -1, -1) == "/" then
+ conf.redirect_uri = string.sub(uri, 1, -2) .. suffix
+ else
+ conf.redirect_uri = uri .. suffix
+ end
+ end
+ core.log.debug("auto set redirect_uri: ", conf.redirect_uri)
end
if not conf.ssl_verify then
diff --git a/docs/en/latest/plugins/openid-connect.md b/docs/en/latest/plugins/openid-connect.md
index 729d5e0..23b5090 100644
--- a/docs/en/latest/plugins/openid-connect.md
+++ b/docs/en/latest/plugins/openid-connect.md
@@ -44,7 +44,7 @@
| bearer_only | boolean | False | false | | When set to `true`, APISIX will only check if the authorization header in the request matches a bearer token. |
| logout_path | string | False | "/logout" | | Path for logging out. |
| post_logout_redirect_uri | string | False | | | URL to redirect to after logging out. |
-| redirect_uri | string | False | "ngx.var.request_uri" | | URI to which the identity provider redirects back to. |
+| redirect_uri | string | False | | | URI to which the identity provider redirects back to. If not configured, APISIX will append the `.apisix/redirect` suffix to determine the default `redirect_uri`. Note that the provider should be properly configured to allow such `redirect_uri` values. |
| timeout | integer | False | 3 | [1,...] | Request timeout time in seconds. |
| ssl_verify | boolean | False | false | | When set to true, verifies the identity provider's SSL certificates. |
| introspection_endpoint | string | False | | | URL of the token verification endpoint of the identity server. |
@@ -229,3 +229,4 @@
- `redirect_uri` needs to be captured by the route where the current APISIX is located. For example, the `uri` of the current route is `/api/v1/*`, `redirect_uri` can be filled in as `/api/v1/callback`;
- `scheme` and `host` of `redirect_uri` (`scheme:host`) are the values required to access APISIX from the perspective of the identity provider.
+- `redirect_uri` should not be the same as the URI of the route. This is because when a user initiates a request to visit the protected resource, the request directly hits the redirection URI with no session cookie in the request, which leads to the `no session state found` error.
diff --git a/docs/zh/latest/plugins/openid-connect.md b/docs/zh/latest/plugins/openid-connect.md
index 766afd5..3ae3fe3 100644
--- a/docs/zh/latest/plugins/openid-connect.md
+++ b/docs/zh/latest/plugins/openid-connect.md
@@ -43,7 +43,7 @@
| bearer_only | boolean | 否 | false | | 当设置为 `true` 时,将仅检查请求头中的令牌(Token)。 |
| logout_path | string | 否 | "/logout" | | 登出路径。 |
| post_logout_redirect_uri | string | 否 | | | 调用登出接口后想要跳转的 URL。 |
-| redirect_uri | string | 否 | "ngx.var.request_uri" | | 身份提供者重定向返回的 URI。 |
+| redirect_uri | string | 否 | | | 身份提供者重定向返回的 URI。如果缺失,则 APISIX 将在当前 URI 之后追加 `.apisix/redirect` 作为默认的 `redirect_uri`。注意,OP 也需要适当配置以允许这种形式的 `redirect_uri`。 |
| timeout | integer | 否 | 3 | [1,...] | 请求超时时间,单位为秒 |
| ssl_verify | boolean | 否 | false | [true, false] | 当设置为 `true` 时,验证身份提供者的 SSL 证书。 |
| introspection_endpoint | string | 否 | | | 用于内省访问令牌的身份提供者的令牌内省端点的 URL。如果未设置,则使用发现文档中提供的内省端点[作为后备](https://github.com/zmartzone/lua-resty-openidc/commit/cdaf824996d2b499de4c72852c91733872137c9c)。 |
@@ -226,3 +226,4 @@
- `redirect_uri` 需要能被当前 APISIX 所在路由捕获,比如当前路由的 `uri` 是 `/api/v1/*`, `redirect_uri` 可以填写为 `/api/v1/callback`;
- `redirect_uri`(`scheme:host`)的 `scheme` 和 `host` 是身份认证服务视角下访问 APISIX 所需的值。
+- `redirect_uri` 不应与路由的 URI 相同。这是因为当用户发起访问受保护资源的请求时,请求会直接指向重定向 URI,而请求中没有会话 cookie,从而导致 `no session state found` 错误。
diff --git a/t/plugin/openid-connect2.t b/t/plugin/openid-connect2.t
index f12001b..29c49ae 100644
--- a/t/plugin/openid-connect2.t
+++ b/t/plugin/openid-connect2.t
@@ -334,3 +334,70 @@
--- timeout: 10s
--- response_body
true
+
+
+
+=== TEST 9: Set up route with plugin matching URI `/hello` with redirect_uri use default value.
+--- 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",
+ "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 10: The value of redirect_uri should be appended to `.apisix/redirect` in the original request.
+--- 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 redirect_uri = uri .. "/.apisix/redirect"
+ 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=' .. redirect_uri) ~= -1 then
+ ngx.say(true)
+ end
+ }
+ }
+--- timeout: 10s
+--- response_body
+true
+--- error_code: 302