I am using jTDS to connect to SQLServer. Internally jTDS uses GSS to obtain a kerberos' service ticket and establish a secure context. Since my app is long lived and my connections are kept alive the entire time I need that kerberos' service ticket to be renewable in order to allow SQL server to renew them on its own (the kdc policies are set to expire all tickets after 12 hours).
What jTDS does to obtain a kerberos token is (more or less) the following:
GSSManager manager = GSSManager.getInstance();
// Oids for Kerberos5
Oid mech = new Oid("1.2.840.113554.1.2.2");
Oid nameType = new Oid("1.2.840.113554.1.2.2.1");
// Canonicalize hostname to create SPN like MIT Kerberos does
GSSName serverName = manager.createName("MSSQLSvc/" + host + ":" + port, nameType);
GSSContext gssContext = manager.createContext(serverName, mech, null, GSSContext.DEFAULT_LIFETIME);
gssContext.requestMutualAuth(false);
gssContext.requestCredDeleg(true);
byte[] ticket = gssContext.initSecContext(new byte[0], 0, 0);
What I suspect is that the ticket I am obtaining is not renewable. I am checking that by doing something like the following:
ExtendedGSSContext extendedContext = (ExtendedGSSContext) gssContext;
boolean[] flags = (boolean[]) extendedContext.inquireSecContext(InquireType.KRB5_GET_TKT_FLAGS);
System.out.println("Renewable = " + flags[8]);
In our particular configuration GSS is getting kerberos TGT from JAAS login module. We have the following variable set to false -Djavax.security.auth.useSubjectCredsOnly=false
and in the login.cfg file we have the following login module configured:
com.sun.security.jgss.krb5.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useKeytTab=true
keyTab="/home/batman/.batman.ktab"
principal="batman@GOTHAMCITY.INT"
storeKey=true
doNotPrompt=true
debug=false
};
Another thing I notice is that the getLifetime()
method of GSSContext
doesn't seem to work. It always returns 2147483647 (max int) no matter what the real lifetime of the ticket is.
I feel confortable with branching jTDS driver, so I can modify the way it establishes a GSS context if needed.
What I tried:
Use native implementation of GSS api:
This works fine for me in terms of obtaining renewable tickets but it imposesses another set of issues (in terms of ensuring that the ticket cache is properly set and tickets in there are properly renew). If I can bypass this option it would be nice. Once thing I observe here is that the getLifetime()
method actually returns the real lifetime in seconds of the ticket.
Reimplementing KerberosLoginModule:
Based on the answer to this question Jaas - Requesting Renewable Kerberos Tickets I reimplemented LoginModule to set the RENEW KDCOption
in KrbAsReqBuilder
before requesting a TGT. That works fine in the sense that I obtain a renewable TGT, but the ticket obtained from that TGT by GSS is still not renewable. If I set a breakpoint in the constructor of the KDCOption object and set the RENEW flag manually on each request (even the KrbTgsReq
done by GSS) it works but making that change productive requires a major rewrite on GSS which I don't feel confortable with.