Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
627 views
in Technique[技术] by (71.8m points)

authentication - How to save Kerberos Service Ticket using a Windows Java client?

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.

I'm experiencing two problems:

  • 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?

  • 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.

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("
Sending '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());
  }

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

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

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

C:Program FilesJavajdk1.8.0_77in>kinit
Password for <user>@<domain>:
New ticket is stored in cache file C:Users<user>krb5cc_<user>

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

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.

EDIT: 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

About the cache >> Looks like you don't specify what is the default cache on your system (cf. env variable KRB5CCNAME) so Java and kinit revert to a hard-coded default. And that's not the same default...

  • your version of kinit clearly uses the Linux standard i.e. a FILE:
  • Java typically uses the Windows standard i.e. the API: managed by the MIT-Kerberos-for-Windows service

Possible workaround: either use the Kerberos UI on Windows to create the TGT, or force Java to use the file cache by setting KRB5CCNAME.

Reference: MIT Kerberos documentation and especially the very last link about hard-coded default

~~~~~~~

About the random time values >> I have no clue.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...