Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions apisix/plugins/openid-connect.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
local core = require("apisix.core")
local ngx_re = require("ngx.re")
local openidc = require("resty.openidc")
local random = require("resty.random")
local fetch_secrets = require("apisix.secret").fetch_secrets
local jsonschema = require('jsonschema')
local string = string
Expand Down Expand Up @@ -347,12 +346,7 @@ function _M.check_schema(conf)
end

if not conf.bearer_only and not conf.session then
core.log.warn("when bearer_only = false, " ..
"you'd better complete the session configuration manually")
conf.session = {
-- generate a secret when bearer_only = false and no secret is configured
secret = ngx_encode_base64(random.bytes(32, true) or random.bytes(32))
}
return false, "property \"session.secret\" is required when \"bearer_only\" is false"
end

local check = {"discovery", "introspection_endpoint", "redirect_uri",
Expand Down
16 changes: 5 additions & 11 deletions docs/en/latest/plugins/openid-connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ The `openid-connect` Plugin supports the integration with [OpenID Connect (OIDC)
| set_userinfo_header | boolean | False | true | | If true and if user info data is available, set the value in the `X-Userinfo` request header. |
| set_refresh_token_header | boolean | False | false | | If true and if the refresh token is available, set the value in the `X-Refresh-Token` request header. |
| session | object | False | | | Session configuration used when `bearer_only` is `false` and the Plugin uses Authorization Code flow. |
| session.secret | string | True | | 16 or more characters | Key used for session encryption and HMAC operation when `bearer_only` is `false`. It is automatically generated and saved to etcd if not configured. When using APISIX in the standalone mode where etcd is no longer the configuration center, the `secret` should be configured. |
| session.secret | string | True | | 16 or more characters | Key used for session encryption and HMAC operation when `bearer_only` is `false`. |
| session.cookie | object | False | | | Cookie configurations. |
| session.cookie.lifetime | integer | False | 3600 | | Cookie lifetime in seconds. |
| session_contents | object | False | | | Session content configurations. If unconfigured, all data will be stored in the session. |
Expand Down Expand Up @@ -231,17 +231,11 @@ To properly configure the redirection URI, make sure that the `redirect_uri` mat

You should also ensure that the `redirect_uri` include the scheme, such as `http` or `https`.

#### 2. Missing Session Secret

If you deploy APISIX in the [standalone mode](/apisix/production/deployment-modes#standalone-mode), make sure that `session.secret` is configured.

User sessions are stored in browser as cookies and encrypted with session secret. The secret is automatically generated and saved to etcd if no secret is configured through the `session.secret` attribute. However, in standalone mode, etcd is no longer the configuration center. Therefore, you should explicitly configure `session.secret` for this Plugin in the YAML configuration center `apisix.yaml`.

#### 3. Cookie Not Sent or Absent
#### 2. Cookie Not Sent or Absent

Check if the [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value) cookie attribute is properly set (i.e. if your application needs to send the cookie cross sites) to see if this could be a factor that prevents the cookie being saved to the browser's cookie jar or being sent from the browser.

#### 4. Upstream Sent Too Big Header
#### 3. Upstream Sent Too Big Header

If you have NGINX sitting in front of APISIX to proxy client traffic, see if you observe the following error in NGINX's `error.log`:

Expand All @@ -253,11 +247,11 @@ If so, try adjusting `proxy_buffers`, `proxy_buffer_size`, and `proxy_busy_buffe

Another option is to configure the `session_content` attribute to adjust which data to store in session. For instance, you can set `session_content.access_token` to `true`.

#### 5. Invalid Client Secret
#### 4. Invalid Client Secret

Verify if `client_secret` is valid and correct. An invalid `client_secret` would lead to an authentication failure and no token shall be returned and stored in session.

#### 6. PKCE IdP Configuration
#### 5. PKCE IdP Configuration

If you are enabling PKCE with the authorization code flow, make sure you have configured the IdP client to use PKCE. For example, in Keycloak, you should configure the PKCE challenge method in the client's advanced settings:

Expand Down
6 changes: 6 additions & 0 deletions docs/en/latest/tutorials/keycloak-oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
"plugins": {
"openid-connect": {
"bearer_only": false,
"session": {
"secret": "change_to_whatever_secret_you_want"
},
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
"discovery": "'"$OIDC_DISCOVERY"'",
Expand All @@ -203,6 +206,9 @@ curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
"plugins": {
"openid-connect": {
"bearer_only": false,
"session": {
"secret": "change_to_whatever_secret_you_want"
},
"use_pkce": true,
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
Expand Down
16 changes: 5 additions & 11 deletions docs/zh/latest/plugins/openid-connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ description: openid-connect 插件支持与 OpenID Connect (OIDC) 身份提供
| set_userinfo_header | boolean || true | | 如果为 true 并且用户信息数据可用,则在 `X-Userinfo` 请求标头中设置值。 |
| set_refresh_token_header | boolean || false | | 如果为 true 并且刷新令牌可用,则在 `X-Refresh-Token` 请求标头中设置值。 |
| session | object || | |`bearer_only``false` 且插件使用 Authorization Code 流程时使用的 Session 配置。 |
| session.secret | string || | 16 个字符以上 |`bearer_only``false` 时,用于 session 加密和 HMAC 运算的密钥,若未配置则自动生成并保存到 etcd。当在独立模式下使用 APISIX 时,etcd 不再是配置中心,需要配置 `secret`|
| session.secret | string || | 16 个字符以上 |`bearer_only``false` 时,用于 session 加密和 HMAC 运算的密钥|
| session.cookie | object || | | Cookie 配置。 |
| session.cookie.lifetime | integer || 3600 | | Cookie 生存时间(秒)。|
| unauth_action | string || auth | ["auth","deny","pass"] | 未经身份验证的请求的操作。设置为 `auth` 时,重定向到 OpenID 提供程序的身份验证端点。设置为 `pass` 时,允许请求而无需身份验证。设置为 `deny` 时,返回 401 未经身份验证的响应,而不是启动授权代码授予流程。|
Expand Down Expand Up @@ -232,17 +232,11 @@ the error request to the redirect_uri path, but there's no session state found

您还应该确保 `redirect_uri` 包含 scheme,例如 `http``https`

#### 2. 缺少 Session Secret

如果您在[standalone 模式](../../../en/latest/deployment-modes.md#standalone)下部署 APISIX,请确保配置了 `session.secret`

用户 session 作为 cookie 存储在浏览器中,并使用 session 密钥进行加密。如果没有通过 `session.secret` 属性配置机密,则会自动生成机密并将其保存到 etcd。然而,在独立模式下,etcd 不再是配置中心。因此,您应该在 YAML 配置中心 `apisix.yaml` 中为此插件显式配置 `session.secret`

#### 3. Cookie 未发送或不存在
#### 2. Cookie 未发送或不存在

检查 [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value) cookie 属性是否已正确设置(即您的应用程序是否需要跨站点发送 cookie),看看这是否会成为阻止 cookie 保存到浏览器的 cookie jar 或从浏览器发送的因素。

#### 4. 上游发送的标头太大
#### 3. 上游发送的标头太大

如果您有 NGINX 位于 APISIX 前面来代理客户端流量,请查看 NGINX 的 `error.log` 中是否观察到以下错误:

Expand All @@ -254,11 +248,11 @@ upstream sent too big header while reading response header from upstream

另一个选项是配置 `session_content` 属性来调整在会话中存储哪些数据。例如,你可以将 `session_content.access_token` 设置为 `true`

#### 5. 无效的客户端密钥
#### 4. 无效的客户端密钥

验证 `client_secret` 是否有效且正确。无效的 `client_secret` 将导致身份验证失败,并且不会返回任何令牌并将其存储在 session 中。

#### 6. PKCE IdP 配置
#### 5. PKCE IdP 配置

如果您使用授权码流程启用 PKCE,请确保您已将 IdP 客户端配置为使用 PKCE。例如,在 Keycloak 中,您应该在客户端的高级设置中配置 PKCE 质询方法:

Expand Down
6 changes: 6 additions & 0 deletions docs/zh/latest/tutorials/keycloak-oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
"plugins": {
"openid-connect": {
"bearer_only": false,
"session": {
"secret": "change_to_whatever_secret_you_want"
},
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
"discovery": "'"$OIDC_DISCOVERY"'",
Expand All @@ -203,6 +206,9 @@ curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
"plugins": {
"openid-connect": {
"bearer_only": false,
"session": {
"secret": "change_to_whatever_secret_you_want"
},
"use_pkce": true,
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
Expand Down
91 changes: 75 additions & 16 deletions t/plugin/openid-connect.t
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ __DATA__
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.openid-connect")
local ok, err = plugin.check_schema({client_id = "a", client_secret = "b", discovery = "c"})
local ok, err = plugin.check_schema({
client_id = "a",
client_secret = "b",
discovery = "c",
session = {secret = "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"}
})
if not ok then
ngx.say(err)
end
Expand All @@ -60,7 +65,11 @@ done
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.openid-connect")
local ok, err = plugin.check_schema({client_secret = "b", discovery = "c"})
local ok, err = plugin.check_schema({
client_secret = "b",
discovery = "c",
session = {secret = "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"}
})
if not ok then
ngx.say(err)
end
Expand All @@ -79,7 +88,12 @@ done
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.openid-connect")
local ok, err = plugin.check_schema({client_id = 123, client_secret = "b", discovery = "c"})
local ok, err = plugin.check_schema({
client_id = 123,
client_secret = "b",
discovery = "c",
session = {secret = "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"}
})
if not ok then
ngx.say(err)
end
Expand Down Expand Up @@ -111,7 +125,10 @@ done
"ssl_verify": false,
"timeout": 10,
"scope": "apisix",
"use_pkce": false
"use_pkce": false,
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -204,7 +221,10 @@ true
"access_token_in_authorization_header": false,
"set_id_token_header": true,
"set_userinfo_header": true,
"set_refresh_token_header": true
"set_refresh_token_header": true,
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -308,7 +328,10 @@ x-userinfo: ey.*
"set_access_token_header": true,
"access_token_in_authorization_header": true,
"set_id_token_header": false,
"set_userinfo_header": false
"set_userinfo_header": false,
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -901,22 +924,20 @@ OIDC introspection failed: invalid token
client_id = "kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
client_secret = "60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa",
discovery = "http://127.0.0.1:1980/.well-known/openid-configuration",
session = {
secret = "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
},
}
local ok, err = plugin.check_schema(s)
if not ok then
ngx.say(err)
end
-- ensure session secret generated when bearer_only = false
-- then remove it from table, because it's a random value that I cannot verify it by response body
assert(s.session and s.session.secret, "no session secret generated")
s.session = nil
ngx.say(json.encode(s))
}
}
--- response_body
{"accept_none_alg":false,"accept_unsupported_alg":true,"access_token_expires_leeway":0,"access_token_in_authorization_header":false,"bearer_only":false,"client_id":"kbyuFDidLLm280LIwVFiazOqjO3ty8KH","client_jwt_assertion_expires_in":60,"client_secret":"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa","discovery":"http://127.0.0.1:1980/.well-known/openid-configuration","force_reauthorize":false,"iat_slack":120,"introspection_endpoint_auth_method":"client_secret_basic","introspection_interval":0,"jwk_expires_in":86400,"jwt_verification_cache_ignore":false,"logout_path":"/logout","realm":"apisix","renew_access_token_on_expiry":true,"revoke_tokens_on_logout":false,"scope":"openid","set_access_token_header":true,"set_id_token_header":true,"set_refresh_token_header":false,"set_userinfo_header":true,"ssl_verify":false,"timeout":3,"token_endpoint_auth_method":"client_secret_basic","unauth_action":"auth","use_nonce":false,"use_pkce":false}
{"accept_none_alg":false,"accept_unsupported_alg":true,"access_token_expires_leeway":0,"access_token_in_authorization_header":false,"bearer_only":false,"client_id":"kbyuFDidLLm280LIwVFiazOqjO3ty8KH","client_jwt_assertion_expires_in":60,"client_secret":"60Op4HFM0I8ajz0WdiStAbziZ-VFQttXuxixHHs2R7r7-CW8GR79l-mmLqMhc-Sa","discovery":"http://127.0.0.1:1980/.well-known/openid-configuration","force_reauthorize":false,"iat_slack":120,"introspection_endpoint_auth_method":"client_secret_basic","introspection_interval":0,"jwk_expires_in":86400,"jwt_verification_cache_ignore":false,"logout_path":"/logout","realm":"apisix","renew_access_token_on_expiry":true,"revoke_tokens_on_logout":false,"scope":"openid","session":{"secret":"jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"},"set_access_token_header":true,"set_id_token_header":true,"set_refresh_token_header":false,"set_userinfo_header":true,"ssl_verify":false,"timeout":3,"token_endpoint_auth_method":"client_secret_basic","unauth_action":"auth","use_nonce":false,"use_pkce":false}
Expand Down Expand Up @@ -1076,7 +1097,10 @@ OIDC introspection failed: invalid jwt: invalid jwt string
"access_token_in_authorization_header": false,
"set_id_token_header": true,
"set_userinfo_header": true,
"post_logout_redirect_uri": "http://127.0.0.1:]] .. ngx.var.server_port .. [[/hello"
"post_logout_redirect_uri": "http://127.0.0.1:]] .. ngx.var.server_port .. [[/hello",
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -1183,7 +1207,10 @@ http://127.0.0.1:.*/hello
"ssl_verify": false,
"timeout": 10,
"scope": "apisix",
"use_pkce": true
"use_pkce": true,
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -1360,7 +1387,10 @@ x-userinfo: ey.*
"discovery": "https://samples.auth0.com/.well-known/openid-configuration",
"redirect_uri": "https://iresty.com",
"post_logout_redirect_uri": "https://iresty.com",
"scope": "openid profile"
"scope": "openid profile",
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -1421,7 +1451,10 @@ true
"discovery": "https://accounts.google.com/.well-known/openid-configuration",
"redirect_uri": "https://iresty.com",
"post_logout_redirect_uri": "https://iresty.com",
"scope": "openid profile"
"scope": "openid profile",
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
}
}
},
"upstream": {
Expand Down Expand Up @@ -1485,6 +1518,9 @@ true
"ssl_verify": false,
"timeout": 10,
"bearer_only": false,
"session": {
"secret": "jwcE5v3pM9VhqLxmxFOH9uZaLo8u7KQK"
},
"use_jwks": true,
"realm": "University",
"introspection_endpoint_auth_method": "client_secret_post",
Expand Down Expand Up @@ -1569,3 +1605,26 @@ true
qr/token validate successfully by \w+/
--- grep_error_log_out
token validate successfully by jwks
=== TEST 41: Missing `session.secret`.
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.openid-connect")
local ok, err = plugin.check_schema({
client_id = "a",
client_secret = "b",
discovery = "c",
})
if not ok then
ngx.say(err)
end
ngx.say("done")
}
}
--- response_body
property "session.secret" is required when "bearer_only" is false
done
Loading
Loading