From c7d406dc7b86ceb01f3ec520978d70fd386af87c Mon Sep 17 00:00:00 2001 From: Weitian LI Date: Fri, 22 Dec 2023 10:49:37 +0800 Subject: [PATCH] fix(openid-connect): the default 'redirect_uri' (#2426) (#7690) Co-authored-by: Traky Deng Co-authored-by: lyy <2424809934@qq.com> --- apisix/plugins/openid-connect.lua | 19 ++++++- docs/en/latest/plugins/openid-connect.md | 3 +- docs/zh/latest/plugins/openid-connect.md | 3 +- t/plugin/openid-connect2.t | 67 ++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/apisix/plugins/openid-connect.lua b/apisix/plugins/openid-connect.lua index dc0c53d2e717..8ed6ab4447ef 100644 --- a/apisix/plugins/openid-connect.lua +++ b/apisix/plugins/openid-connect.lua @@ -86,7 +86,7 @@ local schema = { }, 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 @@ function _M.rewrite(plugin_conf, ctx) 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 729d5e0909a2..23b50906c296 100644 --- a/docs/en/latest/plugins/openid-connect.md +++ b/docs/en/latest/plugins/openid-connect.md @@ -44,7 +44,7 @@ description: OpenID Connect allows the client to obtain user information from th | 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 @@ In this example, the Plugin can enforce that the access token, the ID token, and - `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 766afd51491e..3ae3fe3569e1 100644 --- a/docs/zh/latest/plugins/openid-connect.md +++ b/docs/zh/latest/plugins/openid-connect.md @@ -43,7 +43,7 @@ description: OpenID Connect(OIDC)是基于 OAuth 2.0 的身份认证协议 | 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 @@ curl http://127.0.0.1:9180/apisix/admin/routes/1 \ - `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 f12001b3a801..29c49aedbeb8 100644 --- a/t/plugin/openid-connect2.t +++ b/t/plugin/openid-connect2.t @@ -334,3 +334,70 @@ passed --- 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