会话 cookie 在 OIDC 重定向期间如何丢失?

问题描述 投票:0回答:1

我有一个基于 java 的桌面应用程序(带有 java 服务器),它使用 OIDC 授权代码流和 Okta 进行身份验证。它在多个不同的实例中工作正常,但客户端设置的本地服务器出现故障。我将“state”参数存储在仅服务器 cookie 中,以便我可以根据身份验证响应中的状态值对其进行检查。问题是当我的应用程序服务器收到身份验证响应时,状态 cookie 为空。

我怀疑这与客户端的网络设置有关。我的信息有限,因此我试图找出向他们的 IT 人员询问哪些问题,或者尝试排除故障的步骤。我对他们的设置有两个细节表示怀疑:

  1. 他们有一个影响大部分网络流量的代理。它不会影响应用服务器的流量,但它确实适用于 Okta URL。 (他们没有解释这个代理在做什么,但我在网络日志中找到了它的证据。)
  2. 他们使用带有 Kerberos 的无代理桌面 SSO。

我有尝试登录的用户的网络日志(通过 chrome://net-export/ 收集)。看起来最终重定向回我们的服务器对原始请求没有源依赖性,因此应用程序服务器不知道它应该恢复服务器上的原始 HTTPSession。

在客户端(损坏)示例中,源依赖项指向与 Kerberos 相关的 Okta 服务器的重定向。

如果我进一步追溯依赖关系,它会命中此 Okta URL...

...然后在新套接字处进入同一个 Okta 域的死胡同:

在我的工作示例中,最终重定向的依赖项直接指向应用服务器的原始请求。 收到原始请求后,服务器设置状态 cookie:

我不知道我是否正确解释了这些日志,或者为什么这些依赖链如此不同,但似乎在 Okta 和 Kerberos 之间的通信中的某个地方发生了中断。除了禁用无代理 SSO 之外,还有什么方法可以确认这一点吗?

我感谢对此的任何帮助或见解。

更新:添加 OIDC 实施的详细信息。

当您点击应用程序上的登录按钮时,会发生以下情况:

  1. 桌面客户端启动一个HTTPListener监听某个端口,异步接收最终响应。
  2. 打开系统默认浏览器,访问启动身份验证请求的应用服务器上的 URL。 /login/?port=(端口号也存储为 cookie。)
  3. 生成 PKCE 挑战的状态,存储在 cookie 中。创建身份验证请求并重定向到 ?scope=openid+email+offline_access+groups&response_type=code&redirect_uri=&state=
  4. 用户完成身份验证质询。
  5. 服务器收到身份验证响应。 ?代码=&状态=
  6. 服务器获取状态 cookie 以根据响应中的状态参数进行验证。然后从步骤 2 中获取端口 cookie,并将身份验证结果发送回桌面客户端。

我很高兴进行重构以避免 cookie,但我不确定如何将状态参数值连接回原始状态值。也许这有点矫枉过正,服务器可以只保存一组有效状态并验证返回的参数是否位于该组中的某个位置? (或者实际上是一组状态代码验证器对。)

openid-connect session-cookies kerberos okta
1个回答
1
投票

Cookie 通常只应返回到浏览器客户端。在浏览器之外使用 cookie 是非标准的,并且更有可能遇到基础设施问题。例如,如果请求具有

origin
标头,代理服务器或防火墙可能仅返回 cookie。在某些情况下,有效来源也可能被列入白名单。

桌面客户端中的

state

code_verifier
参数通常存储在应用程序中,而登录则在系统浏览器中运行。这在
RFC8252中进行了解释。有时,人们尝试将网站解决方案用于本机应用程序,但这通常效果不佳。

建议的更新

这里是一些示例代码(在 Node.js 中,您需要将其转换为 Java),显示了在桌面应用程序中实现流程的最典型方法。请求状态只是存储在内存中,然后与响应 URL 中的响应状态进行比较。

export async function login(): Promise<string> { const port = getFreePort(); const redirectUri = `http://127.0.0.1:${port}`; const state = generateRandomString(); const codeVerifier = generateRandomString(); const codeChallenge = generateHash(codeVerifier); const authorizationUrl = buildAuthorizationRequestUrl(redirectUri, state, codeChallenge); return new Promise<string>((resolve, reject) => { let server: Http.Server | null = null; const callback = async (request: Http.IncomingMessage, response: Http.ServerResponse) => { response.end(); server.close(); server = null; const authorizationResponseUrl = request.url!; processAuthorizationResponseUrl(authorizationResponseUrl, state, codeVerifier); } server = Http.createServer(callback); server.listen(port); openSystemBrowser(authorizationUrl); }); }
这可能无法正确解释您所遇到的基础设施问题,但它将消除您的 OAuth 流程中涉及服务器组件或 cookie 的需要。因此,它可能会解决您的客户问题。

© www.soinside.com 2019 - 2024. All rights reserved.