我们有一个可以与外部服务通信的服务器端应用程序。这取决于我们的配置,我们是否使用呼叫我们的用户的凭据、预配置的凭据对这些服务进行身份验证,或者根本不进行身份验证。
外部服务可以使用 HTTP Negotiate 身份验证。对于我们的自定义 HTTP/WebDAV 请求,我们使用 Apache HttpClient,其中我们可以在自己的控制下处理凭据。但对于 JAX-WS 调用(或由第 3 方库调用的纯 HTTP URL),Java 的 HttpUrlConnection 会自行处理身份验证。这就是事情变得奇怪的地方。
据推测,Java 总是尝试使用当前主题的 Kerberos 凭据进行协商。这很好,并且有效。它还可以使用票证缓存(即 kinit 会话或系统会话,如果可以访问),但如果我正确阅读文档 (*),它应该仅在两个条件下这样做:
*) https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/lab/part6.html https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/lab/part6.html
- javax.security.auth.useSubjectCredentialsOnly 显式设置为 false
- 已提供自定义 JAAS 配置,该配置显式将 useTicketCache 设置为 true
事实并非如此。在我们的可重复测试中,如果主题为空,则默认始终使用系统凭据。更糟糕的是,显式地将 useSubjectCredentialsOnly 设置为 true(这应该是默认值)不会改变此行为。到目前为止,我们发现的唯一解决方法是显式提供自定义 JAAS 配置,将 useTicketCache 设置为 false(这又应该是默认值)。
调试 Krb5LoginModule 表明,除非我们配置此解决方法,否则实际上会使用 useTicketCache=true 调用登录模块。
我们可以在所有 Windows 系统上重现这一点。 Linux 似乎表现良好,但我无法详细验证这一点(由于域问题)。
我读的文档有误吗?或者Java实现中存在错误?还是我们的 Windows 系统不稳定?
我们必须告诉客户始终配置一种解决方法,以防止 Java 使用服务用户(而不是向我们的服务发送请求的用户)的凭据秘密调用远程服务,这似乎非常不理想。