如何使用Windows Java客户端保存Kerberos服务票证? [英] How to save Kerberos Service Ticket using a Windows Java client?

查看:903
本文介绍了如何使用Windows Java客户端保存Kerberos服务票证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've written a simple Java HTTP Client that is running under Windows. The client communicates with a web server which requires Kerberos authentication through SPNego.

我遇到两个问题:


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

  • The service ticket is not stored in my credentials cache. After performing a request, I expected to see a Kerberos Service Ticket stored in my credentials cache under C:\Users\<user>\krb5cc_<user> - was I wrong to assume that Java stores service tickets in the credential cache? I'd like to reuse a Service Ticket obtained in Client A for requests in Client B (where both Clients are Java applications on the same machine). Is this possible with Java?

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

If I run the code below one hundred times in a loop, it only works n-times (where n is a random number between 1 and 100). The failing request returns a 401 error message, because Java wasn't able to retrieve a Service ticket (remember: since my application doesn't store service tickets between requests, it tries to obtain a new service ticket from the TGT for every request). I've added the error message to the bottom of this question.

我已经通过kinit创建了一个TGT我的JDK的bin文件夹。以下代码段用于发出简单的GET请求:

I've created a TGT via kinit in my JDK's bin folder. The following code snippet is used for making simple GET requests:

  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's the content of my jaas.conf (as described here):

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

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

I'm running my application with the following parameters:

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

我从未用作krb5.ini我的客户端从域配置中获取正确的KDC。

I'm not using as a krb5.ini since my client obtains the correct KDC from the domain configuration.

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

I can generate a TGT for my credentials cache via the following command:

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年。有趣的是,每次请求都不会发生这种情况。

And finally, here's the exception and Kerberos Debug Output for the case where authorization fails (ref. Problem 2). Please note that ctime is obviously wrong. I've had many different attempts and the timespan for the ctime ranges from 1970 to 2040. Interestingly enough, this doesn't happen for every request.

>>>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)。

I've already tried to work with JAAS using Subject.doAs, but this is causing the same problems. Accesing the server via the browser works fine (although this is not comparable, as the browsers are using the Windows native credentials cache AFAICT).

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

I'd be thankful for some advice on how to debug a problem like this.

编辑:通过 KRB5CCNAME指定凭证缓存的路径显式环境变量,不会改变行为。似乎TGT是从Credentials Cache获得的,但Service Tickets不存储在那里。

Specifiying the path to the credentials cache via the KRB5CCNAME environment variable explicitly, does not change the behavior. It seems like the TGT is obtained from the Credentials Cache but Service Tickets are not stored there.

推荐答案

JAAS不会持久存在进入缓存的票证,您必须使用kinit或通过代码以编程方式调用kinit代码。
我在这个问题上写了一个问题/答案此处

JAAS is not going to persist tickets into the cache, you have to use kinit or invoke kinit code programmatically by your code. I have wrote a SO question/answer on this problem here.

这篇关于如何使用Windows Java客户端保存Kerberos服务票证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆