我编写了一个在Windows下运行的简单Java HTTP客户端。客户端与Web服务器通信,该服务器需要通过SPNego进行Kerberos身份验证。
我遇到了两个问题:
服务票证未存储在我的凭证缓存中。执行请求后,我希望在C:\Users\<user>\krb5cc_<user>
下的证书缓存中看到存储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的内容(如here所述):
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 <user>@<domain>:
New ticket is stored in cache file C:\Users\<user>\krb5cc_<user>
最后,这是授权失败的情况下的异常和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/<spn>@<domain>
msgType is 30
KrbException: Request is a replay (34) - PROCESS_TGS
我已经尝试使用Subject.doAs
使用JAAS,但这会导致同样的问题。通过浏览器访问服务器工作正常(虽然这是不可比的,因为浏览器使用Windows本机凭据缓存AFAICT)。
我会感谢你就如何调试这样的问题提出一些建议。
编辑:明确地通过KRB5CCNAME
环境变量指定凭证缓存的路径,不会改变行为。似乎TGT是从凭证缓存中获得的,但服务票据不存储在那里。
答案 0 :(得分:0)
关于缓存&gt;&gt;看起来您没有指定系统上的默认缓存(参见env变量KRB5CCNAME
),因此Java和kinit恢复为硬编码默认值。这不是默认的......
kinit
版本明确使用Linux标准,即FILE:
API:
可能的解决方法:使用Windows上的Kerberos UI创建TGT,或通过设置KRB5CCNAME
强制Java使用文件缓存。
参考: MIT Kerberos documentation,尤其是关于硬编码默认的最后一个链接
~~~~~~~
关于随机时间值&gt;&gt;我不知道。
答案 1 :(得分:0)
关于偶尔出现的随机时间值:我们发现在udp_preference_limit = 1
中设置krb5.ini
可以解决问题。这有效地告诉Kerberos总是首先尝试使用TCP来发送包。显然,切换到UDP时会出现问题(不确定UDP是问题还是在协议之间切换)。
答案 2 :(得分:0)
JAAS不会将票证持久存储到缓存中,您必须使用kinit或通过代码以编程方式调用kinit代码。 我在这个问题here上写了一个问题/答案。