java Kerberos 身份验证主体 11 错误 - KRB_CRED 未正确生成

java 11 Error with Kerberos Authentication principal - KRB_CRED not generated correctly

java.sql.SQLRecoverableException: IO Error: The service in process is not supported. Operation unavailable (Mechanism level: KRB_CRED not generated correctly.)

当我的 HikariDataSource 试图通过使用 kerberos 作为身份验证方式与我的 oracle 数据库建立连接时,我遇到了这个异常。

我相信这个问题与我的原则没有被接受有关,尽管我的凭证缓存文件在我的其他 java 8 项目中工作得很好。

我认为它与主体有关的原因是因为我有一个在我的服务器上生成的单独的凭据缓存文件,该文件使用与我在本地使用的主体不同的主体。来自我的服务器的凭据缓存文件在本地用于此 java 11 项目时工作得很好。但是,我无法使用该主体在本地生成凭据缓存文件。

此外,我使用的是相同的 krb5.conf 文件,所以我不明白我的委托人是如何被一项服务接受的,但不是另一项服务......我还确保使用 java 11 执行以下命令时 kinit.exe 文件的版本,但我认为这无关紧要。

$kinit -c credential_cache_file instance@domain.realm

使用其他标志,例如 -A -p -f 也会给我一个单独的错误,但是,这种类型的凭据缓存文件对我的任何 java 8java 11 服务。

java.nio.BufferOverflowException: null

编辑: 我实际得到的最低级别错误是这个。

Caused by: sun.security.krb5.KrbException: Invalid option in ticket request. (101)

实际上,更多信息和堆栈跟踪将有助于调试问题。根据以上提供的信息,

kerberos credential 不匹配时,会发生此 exception。然后发生 GSSException 并生成此消息。

Operation unavailable (Mechanism level: KRB_CRED not generated correctly.)

代码流

第一步: 此消息是 Krb5Context class 的一部分。这里的 InquireTypeKRB5_GET_KRB_CRED 表示它是一个属性类型,用于检索发起者即将发送给接受者的 KRB_CRED 消息。
Links: Krb5ContextInquireType

try {
     byte[] krbCred = new KrbCred(tgt, serviceCreds, key).getMessage();
      return new KerberosCredMessage( sender, recipient, krbCred);
    } catch (KrbException | IOException e) {
       GSSException gsse = new GSSException(GSSException.UNAVAILABLE, -1,
                            "KRB_CRED not generated correctly.");
        gsse.initCause(e);
        throw gsse;
   }

第 2 步: 然后它调用 KrbCred class 并且这里验证失败。此 class 封装了 KRB-CRED 消息,客户端使用该消息将其委托的凭据发送到服务器。在条件检查中,服务票证的客户端与票证授予票证中的客户端不匹配。所以,正如你提到的,在我看来这是一个主要问题。 Link : KrbCred

PrincipalName client = tgt.getClient();
PrincipalName tgService = tgt.getServer();
if (!serviceTicket.getClient().equals(client))
    throw new KrbException(Krb5.KRB_ERR_GENERIC,

第 3 步:首先 KrbException 被抛出,然后它被 catch 块捕获,并且 GSSException 被抛回并返回消息 Operation unavailable。 Link:GSSException

Java8 和 Java11 之间的变化

Java 11 中的 kerberos 发生了很多变化。您可以在 changelog 中找到它。例如

Java11Krb5Context of Java 8 compared to Krb5ContextInquireTypeInquireType

可能的解决方案

您正在使用的 Kerberos 客户端目前可能不支持配置文件 (krb5.conf) 中的 'canonicalize' 设置。因此,无法自定义名称规范化行为。如果 sun.security.krb5.disableReferralsfalse,客户端将在每个 TGT 请求中声明支持它,并且 KDC 服务可能会更改客户端名称。

JDK 11:JDK Kerberos 实现现在支持 krb5.conf 文件中的“canonicalize”标志。设置为真时。 新的默认行为不同于以前的版本,在以前的版本中,客户端总是在 TGTKDC 服务的请求中请求名称规范化(前提是 RFC 6806 的支持没有被 sun.security.krb5.disableReferrals 系统或安全属性)

这个问题也出现在少数 Java 8 版本 (1.8.0_242) 中。您可以尝试重现工单中的示例。 JDK-8239385
更多信息 JDK-8244465

Cross-Realm 默认启用推荐支持,5 是允许的最大推荐跃点数。要关闭它,请将 sun.security.krb5.disableReferrals 安全或系统 属性 设置为 false。要配置自定义最大引荐跃点数,请将 sun.security.krb5.maxReferrals 安全性或系统 属性 设置为任何正值。

您可以尝试更改 JAAS 配置以使用预先使用 kinit 创建的票证缓存中的票证。
您也可以尝试升级 java 版本。

评论区讨论更新:

by: sun.security.krb5.KrbException: Invalid option in ticket request. (101)

这可以链接到您的 krb5.conf 中的 proxiable=true。删除该值有助于解决问题。

Kerberos authentication fails with “java.nio.BufferOverflowException"

此问题可能与 JDBC 驱动程序有关。当前版本可能不支持该操作。升级或降级 oracle jdbc driver 可能会导致解决。