如何使用Windows Java客户端保存Kerberos服务票证?

我编写了一个在Windows下运行的简单Java HTTP客户端。 客户端与需要通过SPNego进行Kerberos身份validation的Web服务器进行通信。

我遇到了两个问题:

  • 服务票证不存储在我的凭证缓存中。 执行请求后,我希望在C:\Users\\krb5cc_下看到存储在我的凭证缓存中的Kerberos服务票证 – 假设Java将服务票据存储在凭证缓存中,我是错误的吗? 我想重新使用客户端A中获取的服务票据来处理客户端B中的请求(其中两个客户端都是同一台计算机上的Java应用程序)。 这可能与Java有关吗?

  • 如果我在循环中运行下面的代码一百次,它只能工作n次(其中n是1到100之间的随机数)。 失败的请求返回401错误消息,因为Java无法检索服务票证(请记住:由于我的应用程序不在请求之间存储服务票证,因此它会尝试从TGT为每个请求获取新的服务票证) 。 我已将错误消息添加到此问题的底部。

我在JDK的bin文件夹中通过kinit创建了一个TGT。 以下代码段用于制作简单的GET请求:

  static void testJavaHttpKerberosAuthentication() throws IOException { URL obj = new URL(URI); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); int responseCode = con.getResponseCode(); System.out.println("\nSending 'GET' request to URL : " + URI); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); //print result System.out.println(response.toString()); } 

这是我的jaas.conf的内容(如这里所述):

 com.sun.security.jgss.krb5.initiate { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=false useTicketCache=true; }; 

我正在使用以下参数运行我的应用程序:

 -Djava.security.auth.login.config=D:\jaas.conf -Dsun.security.krb5.debug=true -Djavax.security.auth.useSubjectCredsOnly=false 

我不是用作krb5.ini,因为我的客户端从域配置中获取了正确的KDC。

我可以通过以下命令为我的凭据缓存生成TGT:

 C:\Program Files\Java\jdk1.8.0_77\bin>kinit Password for @: New ticket is stored in cache file C:\Users\\krb5cc_ 

最后,这是授权失败的情况下的exception和Kerberos调试输出(参考问题2)。 请注意,ctime显然是错误的。 我有很多不同的尝试,ctime的时间范围从1970年到2040年。有趣的是,每次请求都不会发生这种情况。

 >>>KRBError: cTime is Wed Jun 07 12:24:03 CEST 2017 1496831043000 sTime is Tue Mar 29 16:38:24 CEST 2016 1459262304000 suSec is 283371 error code is 34 error Message is Request is a replay sname is HTTP/@ msgType is 30 KrbException: Request is a replay (34) - PROCESS_TGS 

我已经尝试使用Subject.doAs与JAAS合作,但这导致了同样的问题。 通过浏览器访问服务器工作正常(虽然这是不可比的,因为浏览器使用Windows本机凭证缓存AFAICT)。

我要感谢有关如何调试这样的问题的一些建议。

编辑:明确地通过KRB5CCNAME环境变量指定凭证高速缓存的路径,不会改变行为。 似乎TGT是从凭证缓存中获得的,但服务票证不存储在那里。

关于缓存>>看起来您没有指定系统上的默认缓存(参见env变量KRB5CCNAME ),因此Java和kinit将恢复为硬编码默认值。 这不是默认的……

  • 您的kinit版本明显使用Linux标准,即FILE:
  • Java通常使用Windows标准,即API:由MIT-Kerberos-for-Windows服务管理

可能的解决方法:使用Windows上的Kerberos UI创建TGT,或通过设置KRB5CCNAME强制Java使用文件缓存。

参考: MIT Kerberos文档 ,特别是关于硬编码默认值的最后一个链接

~~~~~~~

关于随机时间值>>我不知道。

关于偶尔出现的随机时间值:我们发现在udp_preference_limit = 1中设置udp_preference_limit = 1可以解决问题。 这有效地告诉Kerberos总是首先尝试使用TCP来发送包。 显然,切换到UDP时会出现问题(不确定UDP是问题还是在协议之间切换)。

JAAS不会将票证持久存储到缓存中,您必须使用kinit或通过代码以编程方式调用kinit代码。 我在这里写了一个关于这个问题的问题/答案。