Kerberos: Renew almost expired tickets and detect expired TGT in cache => try to relogin

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@2071 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2013-03-25 11:40:07 +00:00
parent 5b08df4bc2
commit acda06a8d8
2 changed files with 51 additions and 27 deletions

View File

@ -22,8 +22,10 @@ import davmail.Settings;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.ietf.jgss.*; import org.ietf.jgss.*;
import javax.security.auth.RefreshFailedException;
import javax.security.auth.Subject; import javax.security.auth.Subject;
import javax.security.auth.callback.*; import javax.security.auth.callback.*;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
@ -142,15 +144,7 @@ public class KerberosHelper {
Object result = internalInitSecContext(protocol, host, delegatedCredentials, token); Object result = internalInitSecContext(protocol, host, delegatedCredentials, token);
if (result instanceof GSSException) { if (result instanceof GSSException) {
LOGGER.info("KerberosHelper.initSecurityContext exception code " + ((GSSException) result).getMajor() + " minor code " + ((GSSException) result).getMinor() + " message " + ((GSSException) result).getMessage()); LOGGER.info("KerberosHelper.initSecurityContext exception code " + ((GSSException) result).getMajor() + " minor code " + ((GSSException) result).getMinor() + " message " + ((GSSException) result).getMessage());
throw (GSSException) result;
// recreate login context
clientReLogin();
result = internalInitSecContext(protocol, host, delegatedCredentials, token);
if (result instanceof GSSException) {
LOGGER.info("KerberosHelper.initSecurityContext exception code " + ((GSSException) result).getMajor() + " minor code " + ((GSSException) result).getMinor() + " message " + ((GSSException) result).getMessage());
throw (GSSException) result;
}
} }
LOGGER.debug("KerberosHelper.initSecurityContext return " + ((byte[]) result).length + " bytes token"); LOGGER.debug("KerberosHelper.initSecurityContext return " + ((byte[]) result).length + " bytes token");
@ -162,14 +156,14 @@ public class KerberosHelper {
public Object run() { public Object run() {
Object result; Object result;
GSSContext context = null;
try { try {
GSSManager manager = GSSManager.getInstance(); GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName(protocol + "/" + host, null); GSSName serverName = manager.createName(protocol + "/" + host, null);
// Kerberos v5 OID // Kerberos v5 OID
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2"); Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
GSSContext context = manager.createContext(serverName, krb5Oid, delegatedCredentials, context = manager.createContext(serverName, krb5Oid, delegatedCredentials, GSSContext.DEFAULT_LIFETIME);
GSSContext.DEFAULT_LIFETIME);
//context.requestMutualAuth(true); //context.requestMutualAuth(true);
// TODO: used by IIS to pass token to Exchange ? // TODO: used by IIS to pass token to Exchange ?
@ -178,6 +172,14 @@ public class KerberosHelper {
result = context.initSecContext(token, 0, token.length); result = context.initSecContext(token, 0, token.length);
} catch (GSSException e) { } catch (GSSException e) {
result = e; result = e;
} finally {
if (context != null) {
try {
context.dispose();
} catch (GSSException e) {
LOGGER.debug("KerberosHelper.internalInitSecContext " + e + " " + e.getMessage());
}
}
} }
return result; return result;
} }
@ -191,23 +193,37 @@ public class KerberosHelper {
*/ */
public static void clientLogin() throws LoginException { public static void clientLogin() throws LoginException {
synchronized (LOCK) { synchronized (LOCK) {
if (clientLoginContext != null) {
// check cached TGT
for (Object ticket : clientLoginContext.getSubject().getPrivateCredentials(KerberosTicket.class)) {
KerberosTicket kerberosTicket = (KerberosTicket) ticket;
if (kerberosTicket.getServer().getName().startsWith("krbtgt") && !kerberosTicket.isCurrent()) {
LOGGER.debug("KerberosHelper.clientLogin cached TGT expired, try to relogin");
clientLoginContext = null;
}
}
}
if (clientLoginContext == null) { if (clientLoginContext == null) {
final LoginContext localLoginContext = new LoginContext("spnego-client", KERBEROS_CALLBACK_HANDLER); final LoginContext localLoginContext = new LoginContext("spnego-client", KERBEROS_CALLBACK_HANDLER);
localLoginContext.login(); localLoginContext.login();
clientLoginContext = localLoginContext; clientLoginContext = localLoginContext;
} }
} // try to renew almost expired tickets
} for (Object ticket : clientLoginContext.getSubject().getPrivateCredentials(KerberosTicket.class)) {
KerberosTicket kerberosTicket = (KerberosTicket) ticket;
/** LOGGER.debug("KerberosHelper.clientLogin ticket for " + kerberosTicket.getServer().getName() + " expires at " + kerberosTicket.getEndTime());
* Recreate client Kerberos context. if (kerberosTicket.getEndTime().getTime() < System.currentTimeMillis() + 10000) {
* if (kerberosTicket.isRenewable()) {
* @throws LoginException on error try {
*/ kerberosTicket.refresh();
public static void clientReLogin() throws LoginException { } catch (RefreshFailedException e) {
synchronized (LOCK) { LOGGER.debug("KerberosHelper.clientLogin failed to renew ticket " + kerberosTicket.toString());
clientLoginContext = null; }
clientLogin(); } else {
LOGGER.debug("KerberosHelper.clientLogin ticket is not renewable");
}
}
}
} }
} }
@ -273,6 +289,7 @@ public class KerberosHelper {
public Object run() { public Object run() {
Object result; Object result;
SecurityContext securityContext = new SecurityContext(); SecurityContext securityContext = new SecurityContext();
GSSContext context = null;
try { try {
GSSManager manager = GSSManager.getInstance(); GSSManager manager = GSSManager.getInstance();
@ -282,7 +299,7 @@ public class KerberosHelper {
GSSCredential.DEFAULT_LIFETIME, GSSCredential.DEFAULT_LIFETIME,
krb5oid, krb5oid,
GSSCredential.ACCEPT_ONLY/* server mode */); GSSCredential.ACCEPT_ONLY/* server mode */);
GSSContext context = manager.createContext(serverCreds); context = manager.createContext(serverCreds);
securityContext.token = context.acceptSecContext(token, 0, token.length); securityContext.token = context.acceptSecContext(token, 0, token.length);
if (context.isEstablished()) { if (context.isEstablished()) {
@ -298,13 +315,20 @@ public class KerberosHelper {
result = securityContext; result = securityContext;
} catch (GSSException e) { } catch (GSSException e) {
result = e; result = e;
} finally {
if (context != null) {
try {
context.dispose();
} catch (GSSException e) {
LOGGER.debug("KerberosHelper.acceptSecurityContext " + e + " " + e.getMessage());
}
}
} }
return result; return result;
} }
}); });
if (result instanceof GSSException) { if (result instanceof GSSException) {
// TODO: manage error codes LOGGER.info("KerberosHelper.acceptSecurityContext exception code " + ((GSSException) result).getMajor() + " minor code " + ((GSSException) result).getMinor() + " message " + ((GSSException) result).getMessage());
LOGGER.info("KerberosHelper.acceptSecurityContext exception code " + ((GSSException) result).getMajor() + " message" + ((GSSException) result).getMessage());
throw (GSSException) result; throw (GSSException) result;
} }
return (SecurityContext) result; return (SecurityContext) result;

View File

@ -36,7 +36,7 @@ import java.util.HashMap;
* <p/> * <p/>
*/ */
public class KerberosLoginConfiguration extends Configuration { public class KerberosLoginConfiguration extends Configuration {
protected static final Logger LOGGER = Logger.getLogger(KerberosHelper.class); protected static final Logger LOGGER = Logger.getLogger(KerberosLoginConfiguration.class);
protected static final AppConfigurationEntry[] CLIENT_LOGIN_MODULE; protected static final AppConfigurationEntry[] CLIENT_LOGIN_MODULE;
protected static final AppConfigurationEntry[] SERVER_LOGIN_MODULE; protected static final AppConfigurationEntry[] SERVER_LOGIN_MODULE;