Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain renewable kerberos tickets using java GSS+JAAS

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="[email protected]"
      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.

like image 280
Claudio Avatar asked Nov 09 '22 16:11

Claudio


1 Answers

For administrators, the fact that Kerberos tickets have lifetime is an important security feature. User knows a password, so he/she may get a new ticket at any moment. But for intruder it's a problem - after the ticket expires, it can't be used to break into system. Administrators want this lifetime to be as short as possible, but not too short (like 1 hour) because users would generate like 10x more login requests than now, and it would be tough for ActiveDirectory to handle.

When we need to authenticate with Kerberos, we should use connection pooling (and DataSource). To use this feature in jTDS you need to add ConnectionPoolImplementation (recommended: DBCP or c3p0, see: http://jtds.sourceforge.net/features.html).

If you'd like to write your application using older way of connecting to database (without datasource, i.e. creating a connection and keeping it alive because it's expensive to create..) then the next obstacle would be 'renew lifetime'. In ActiveDirectory Kerberos tickets can be by default renewed within 7 days. There's a global setting in AD which allows to set there 0 (an indefinite renew lifetime), but you'd need to persuade Domain Administrator to lower security of whole domain just because one service wouldn't run without that.

like image 118
greenmarker Avatar answered Nov 14 '22 23:11

greenmarker