Java8中的Kerberos/SPNEGO服务器端身份验证更改

Java8中的Kerberos/SPNEGO服务器端身份验证更改,java,java-8,kerberos,spnego,Java,Java 8,Kerberos,Spnego,我正在尝试将应用程序从使用java7u51更改为java8u40,但SSO身份验证失败。客户端没有更改,它使用JNA windows调用(Secur32.INSTANCE.InitializeSecurityContext),但服务器不再接受票据。服务器代码没有改变,但它使用的标准java库似乎已经改变了。服务器在linux下运行 服务器代码如下。在我的windows机器上,我编写了一个包含票据的文件,以便运行下面的代码进行测试。我有一个非常高的时钟偏移设置,这样我就可以根据票进行测试。为了以防

我正在尝试将应用程序从使用java7u51更改为java8u40,但SSO身份验证失败。客户端没有更改,它使用JNA windows调用(
Secur32.INSTANCE.InitializeSecurityContext
),但服务器不再接受票据。服务器代码没有改变,但它使用的标准java库似乎已经改变了。服务器在linux下运行

服务器代码如下。在我的windows机器上,我编写了一个包含票据的文件,以便运行下面的代码进行测试。我有一个非常高的时钟偏移设置,这样我就可以根据票进行测试。为了以防万一,我已经用java7u51编写了客户端票据,但这并没有帮助。当我在java7中运行下面的服务器代码时,同样的代码也可以正常工作

失败的位是
isEstablished
返回false。没有有用的调试信息
isEstablished
返回false意味着需要更多的回合,但过去并非如此,我认为不应该如此

有人知道在java8中失败的原因吗?这不仅仅是更新40的问题,它在早期的Java8版本中失败了

谢谢

Properties.setProp("sun.security.krb5.debug", "true")
Properties.setProp("java.security.krb5.realm", "xxxx")
Properties.setProp("java.security.krb5.kdc", "xxxx")
Properties.setProp("java.security.krb5.conf", url(getClass, "/krb5.conf.auth").toExternalForm)
Properties.setProp("java.security.auth.login.config", url(getClass, "/jaas.conf.auth").toExternalForm)
Properties.setProp("javax.security.auth.useSubjectCredsOnly", "true")

val loginCtx: LoginContext = new LoginContext("Server", new LoginCallbackHandler(password))
loginCtx.login()
val subject = loginCtx.getSubject
val ticket = StringIO.readStringFromFile(new File("/tmp/ticket"))
val decoder: BASE64Decoder = new BASE64Decoder
val serviceTicket = decoder.decodeBuffer(ticket)

val user = Subject.doAs(subject, new PrivilegedAction[Option[String]]() {
  def run = {
    try {
      val manager = GSSManager.getInstance
      val context: GSSContext = manager.createContext(null: GSSCredential)
      val arrayOfBytes = context.acceptSecContext(serviceTicket, 0, serviceTicket.length)
      // we ignore arrayOfBytes
      assert(context.isEstablished, "Failed to establish context: " + context)
      val username = context.getSrcName.toString
      Some(username)
    } catch {
      case e: Exception =>
        println("failed: " + e.getMessage)
        None
    }
  }
})

krb5.conf.auth
[libdefaults]
default_realm = XXX
allow_weak_crypto=true
default_tkt_enctypes = rc4-hmac des-cbc-md5 des-cbc-crc des3-cbc-sha1
default_tgs_enctypes = rc4-hmac des-cbc-md5 des-cbc-crc des3-cbc-sha1
permitted_enctypes = rc4-hmac des-cbc-md5 des-cbc-crc des3-cbc-sha1
default_checksum = rsa-md5
kdc_timesync = 0
kdc_default_options = 0x40000010
clockskew = 30000
check_delegate = 0
ccache_type = 3
kdc_timeout = 60000
forwardable = true
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h

#excluding realms and domain_realm

jaas.conf.auth (server section)

Server {
   com.sun.security.auth.module.Krb5LoginModule required
     useKeyTab=false
     debug=true
     isInitiator=false
     storeKey=true
     useTicketCache=false
     principal="XXX";
};
更新:如果这有帮助。我认为客户端正在发送一个SPNEGO票证,因为如果我试图强制上下文只接受Kerberos(1.2.840.113554.1.2.2),我会得到错误
失败:找不到以下内容的凭据:1.3.6.1.5.5.2用法:接受

更新2:这不是真正的答案,但是如果我改变windows客户端创建票据的方式,它就会工作。因此,如果不创建SPNEGO包装的票证,而是创建一个仅Kerberos的票证,那么Java8将接受该票证。因此,将下面的“协商”更改为“Kerberos”可以解决问题

Secur32.INSTANCE.AcquireCredentialsHandle(
      servicePrincipalName,
      "Negotiate", // Change to "Kerberos"
      new NativeLong(Sspi.SECPKG_CRED_OUTBOUND),
      null,
      authIdentity.getPointer,
      null,
      null,
      phClientCredential,
      ptsClientExpiry)

Kerberos/SPNEGO是一个浪费域

根据我的想法,下面是一个快速检查清单,希望能有所帮助

  • 你重新生成你的键表了吗?是否使用与服务器端使用的相同的JDK
  • 您的服务器是否在正确的用户(如密钥选项卡中所定义)下运行
  • 您是否选择“永不过期”选项生成它们
  • 你需要256位加密吗? 可以看到键入(键类型18=AES-256):

    %JAVA\u HOME%\bin\klist-e-f-a-k XX.keytab

    如果是,您是否添加了本地_policy.jar US\u export\u policy.jar在%JAVA\u HOME%\jre\lib\security下?确保KVNO值与您获得的列表中的值相同。理想情况下,您应该只看到一个输出

  • 您的SPN可ping吗

  • 您的KDC服务器列表正确吗
  • 请注意krb5.conf。有问题。即使在Windows环境中也似乎区分大小写

  • Kerberos可能很难设置。祝你好运。

    试着用“NTLM”而不是“协商”,告诉我它是否有效。我也有类似的问题。java8是否可能会放弃对
    allow\u-weak\u-crypto=true
    的支持?java8将allow\u-weak\u-crypto的默认值更改为false,因此除非显式指定为true,否则不能使用DES: