Java + Kerberos - 禁用反向 DNS 查找

Java + Kerberos - disable reverse DNS lookup

我们正在使用 Apache HttpClient 库连接到 Kerberos 保护的 REST 端点,该端点位于为多个应用程序提供服务的负载平衡器之后,因此正向和反向 DNS 查找结果不匹配。

虽然我们可以通过在 krb5.conf 文件中设置 rdns=false 来使用 cURL 成功建立经过身份验证的会话,但在 Java 中似乎不可能做到这一点 - 它只是忽略了这个设置并且总是执行反向 DNS 查找,由于不匹配,这当然会导致握手失败。

我没有找到太多关于这个问题的信息,但我确实找到了这个打开的 Jira 项目,它解释了我们看到的行为..但没有提供任何解决方法: https://bugs.openjdk.java.net/browse/JDK-8189361

到目前为止,我发现的唯一可行的解​​决方法是使用自定义名称服务提供商来 "hijack" 反向 DNS 查找和 return 所需的主机名。
这方面的信息也非常稀少,但我发现这篇 12 年前的博文似乎仍然有效(尽管感觉像是一个非常肮脏的 hack):
http://rkuzmik.blogspot.co.il/2006/08/local-managed-dns-java_11.html

但是感觉我可能在这里遗漏了一些东西,因为关于这个问题的信息似乎很少..

在 Java 中,是否有其他人在执行 Kerberos 时遇到禁用反向 DNS 查找的问题?如果有,你是怎么解决的。

上周我在使用 VIP 时遇到了同样的错误,但反向 dns 返回给我物理服务器的 FQDN。 不幸的是,我没有直接使用 HttpClient-4.5.1 库,而是在幕后使用它的软件;出于这个原因,我一直在寻找一种不涉及该软件源代码的解决方案。 不幸的是,我确实进行了大量尝试(jvm spi.dns、jvm gss native、dnsjava.jar、...),但都没有成功。 最后,"dirty solution" 对我来说是重建 HttpClient jar,在其方法 "String resolveCanonicalHostname(final String host)".

上更改 class "org.apache.http.impl.auth.GGSSchemeBase"

对于可能的 "good solution",我看到这个 class 在其构造函数中直接接收参数 "boolean useCanonicalHostname" 因此,如果您可以直接使用 HttpClient 库,则可能有一种在某处将此参数设置为 false 并将其向下传播到生成 kerberos 服务票证的 class 的方法(如果参数为 false,则不进行 rdns 检查,而是使用主机字符串)。

希望这个提示能帮到你。

BR

塞缪尔

对于使用 Apache HttpClient 库遇到相同问题的任何人,以下代码有效 - 重要的一点是 SPNegoSchemeFactory 的构造函数,它是:

public SPNegoSchemeFactory(final boolean stripPort, final boolean useCanonicalHostname)

下面是我现在使用的 Scala 代码:

  private val registry = RegistryBuilder
    .create()
    .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true,false))
    .build()
    .asInstanceOf[Lookup[AuthSchemeProvider]]

  private val credentialsProvider = new BasicCredentialsProvider

  private val useJaasCreds = new Credentials()
  {
    def getPassword: String = null

    def getUserPrincipal: Principal = null
  }

  credentialsProvider.setCredentials(new AuthScope(null, -1, null), useJaasCreds)

  private val httpClient = HttpClientBuilder
    .create()
    .setDefaultAuthSchemeRegistry(registry)
      .setDefaultCredentialsProvider(credentialsProvider)
    .build()

我遇到了同样的问题,经过调查发现 none 现有 Java HTTP/Kerberos 客户端使您可以完全控制 SPN 的生成。所以我开始研究一个独立的库,它允许生成和验证 Authorization: Negotiate XXX / WWW-Authenticate: Negotiate XXX HTTP headers.

叫做Kerb4J

假设您有一个域 cname.provider.acme.com,它是域 a.provider.acme.com 的 CNAME(又名别名)其规范 DNS 名称(即在反向 DNS 查找后解析)是 ptr.provider.acme.com

您想使用您最喜欢的 HTTP 客户端向 cname.provider.acme.com 发出请求,但不希望它发出任何请求在 SPN 计算期间对 DNS 的额外操作。

URL url = new URL("http://cname.provider.acme.com/api/operation1");
SpnegoContext context = spnegoClient.createContext("http://cname.provider.acme.com"); // Will result in HTTP/cname.provider.acme.com SPN
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());

使用 Kerb4J,您甚至可以使用任意 SPN 发出 SPNEGO 保护的请求(在本地机器上测试代码时有用的说:

URL url = new URL("http://localhost:8080/api/operation1");
SpnegoContext context = spnegoClient.createContext("http://cname.provider.acme.com"); // Will result in HTTP/cname.provider.acme.com SPN
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());

Maven Central 中有可用的发布版本。

免责声明:我是 Kerb4J 的作者。