我们有一个可以与外部服务通信的服务器端应用程序。这取决于我们的配置,我们是否使用调用我们的用户的凭据、预配置的凭据来对这些服务进行身份验证,或者根本不进行身份验证。
外部服务可以使用 HTTP Negotiate 身份验证。对于我们的自定义 HTTP/WebDAV 请求,我们使用 Apache HttpClient,其中我们可以在自己的控制下处理凭据。但对于 JAX-WS 调用(或由第 3 方库调用的纯 HTTP URL),Java 的 HttpUrlConnection 会自行处理身份验证。这就是事情变得奇怪的地方。
据说 Java 总是尝试使用当前主题的 Kerberos 凭据进行协商。这很好,并且有效。它还可以使用票证缓存(即 kinit session 或系统 session ,如果可以访问),但如果我正确阅读文档 (*),它应该只在两个条件下这样做:
*) 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 使用服务用户的凭据(而不是向我们的服务发送请求的用户) secret 调用远程服务,这似乎非常不理想。
最佳答案
至少在我刚刚调试过的 Linux 上的 Java 8 u 131 代码中,函数 sun.security.jgss.GSSUtil.useSubjectCredsOnly(GSSCaller caller) 被硬编码为返回 false 如果调用者是HttpCaller的一个实例。
对于其他类型的调用者,将检查 javax.security.auth.useSubjectCredsOnly 属性。
关于Java 在不应该使用 Kerberos TicketCache 时自动使用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43660265/