我使用jTDS连接到SQLServer.在内部,jTDS使用GSS获取kerberos的服务票证并建立安全的上下文.由于我的应用程序是长期存在的,并且我的连接一直保持活动,所以我需要将kerberos的服务票据更新,以便允许SQL服务器自行续订(kdc策略设置为在12小时后使所有票证到期) ).
jTDS获取kerberos令牌的做法(或多或少)如下:
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);
我怀疑的是我获得的机票不可更新.我正在通过执行以下操作来检查:
ExtendedGSSContext extendedContext = (ExtendedGSSContext) gssContext;
boolean[] flags = (boolean[]) extendedContext.inquireSecContext(InquireType.KRB5_GET_TKT_FLAGS);
System.out.println("Renewable = " + flags[8]);
在我们的特定配置中,GSS从JAAS登录模块获取kerberos TGT.我们将以下变量设置为false -Djavax.security.auth.useSubjectCredsOnly = false,并在login.cfg文件中配置以下登录模块:
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
};
我注意到的另一件事是GSSContext的getLifetime()方法似乎不起作用.无论故障单的实际生命周期是什么,它总是返回2147483647(max int).
我对分支jTDS驱动程序感到很自在,因此我可以根据需要修改它建立GSS上下文的方式.
我尝试了什么:
使用GSS api的本机实现:
这对于我来说在获取可更新票证方面效果很好,但它会产生另一组问题(在确保正确设置票证缓存和正确续订票证方面).如果我可以绕过这个选项那就太好了.一旦我在这里观察到的是,getLifetime()方法实际上返回了票证的实际生命周期(以秒为单位).
重新实现KerberosLoginModule:
根据这个问题Jaas – Requesting Renewable Kerberos Tickets的答案,我重新实现了LoginModule,以便在请求TGT之前在KrbAsReqBuilder中设置RENEW KDCOption.从我获得可再生TGT的意义上来说这很好,但GSS从TGT获得的机票仍然不可再生.如果我在KDCOption对象的构造函数中设置一个断点并在每个请求上手动设置RENEW标志(甚至是由GSS完成的KrbTgsReq)它可以工作,但是要使这个变化有效,需要在GSS上进行重大改写,我觉得不舒服.