From 5b08df4bc24261887370f0f91d3fd626f1ef00af Mon Sep 17 00:00:00 2001 From: mguessan Date: Sun, 24 Mar 2013 22:54:18 +0000 Subject: [PATCH] Kerberos: Handle client context timeout, try to recreate context git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@2070 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- src/java/davmail/http/KerberosHelper.java | 73 +++++++++++++++++------ src/java/davmail/http/SpNegoScheme.java | 4 +- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/java/davmail/http/KerberosHelper.java b/src/java/davmail/http/KerberosHelper.java index aaa8af6e..31fb6e24 100644 --- a/src/java/davmail/http/KerberosHelper.java +++ b/src/java/davmail/http/KerberosHelper.java @@ -71,6 +71,9 @@ public class KerberosHelper { // TODO: get username and password from dialog } } + if (principal == null) { + throw new IOException("KerberosCallbackHandler: failed to retrieve principal"); + } ((NameCallback) callbacks[i]).setName(principal); } else if (callbacks[i] instanceof PasswordCallback) { @@ -83,6 +86,9 @@ public class KerberosHelper { password = inReader.readLine(); } } + if (password == null) { + throw new IOException("KerberosCallbackHandler: failed to retrieve password"); + } ((PasswordCallback) callbacks[i]).setPassword(password.toCharArray()); } else { @@ -92,17 +98,26 @@ public class KerberosHelper { } } + public static void setPrincipal(String principal) { + KERBEROS_CALLBACK_HANDLER.principal = principal; + } + + public static void setPassword(String password) { + KERBEROS_CALLBACK_HANDLER.password = password; + } + /** * Get response Kerberos token for host with provided token. * - * @param host target host - * @param token input token + * @param protocol target protocol + * @param host target host + * @param token input token * @return response token * @throws GSSException on error * @throws LoginException on error */ - public static byte[] initSecurityContext(final String host, final byte[] token) throws GSSException, LoginException { - return initSecurityContext(host, null, token); + public static byte[] initSecurityContext(final String protocol, final String host, final byte[] token) throws GSSException, LoginException { + return initSecurityContext(protocol, host, null, token); } /** @@ -110,6 +125,7 @@ public class KerberosHelper { * Used to authenticate with target host on a gateway server with client credentials, * gateway must have its own principal authorized for delegation * + * @param protocol target protocol * @param host target host * @param delegatedCredentials client delegated credentials * @param token input token @@ -117,20 +133,38 @@ public class KerberosHelper { * @throws GSSException on error * @throws LoginException on error */ - public static byte[] initSecurityContext(final String host, final GSSCredential delegatedCredentials, final byte[] token) throws GSSException, LoginException { - LOGGER.debug("KerberosHelper.initSecurityContext " + host + " " + token.length + " bytes token"); + public static byte[] initSecurityContext(final String protocol, final String host, final GSSCredential delegatedCredentials, final byte[] token) throws GSSException, LoginException { + LOGGER.debug("KerberosHelper.initSecurityContext " + protocol + "/" + host + " " + token.length + " bytes token"); - // TODO: handle ticket expiration ? // create client login context clientLogin(); - Object result = Subject.doAs(clientLoginContext.getSubject(), new PrivilegedAction() { + Object 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()); + + // 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"); + return (byte[]) result; + } + + protected static Object internalInitSecContext(final String protocol, final String host, final GSSCredential delegatedCredentials, final byte[] token) { + return Subject.doAs(clientLoginContext.getSubject(), new PrivilegedAction() { public Object run() { Object result; try { GSSManager manager = GSSManager.getInstance(); - GSSName serverName = manager.createName("HTTP/" + host, null); + GSSName serverName = manager.createName(protocol + "/" + host, null); // Kerberos v5 OID Oid krb5Oid = new Oid("1.2.840.113554.1.2.2"); @@ -148,15 +182,6 @@ public class KerberosHelper { return result; } }); - if (result instanceof GSSException) { - // TODO: manage error codes - LOGGER.info("KerberosHelper.initSecurityContext exception code " + ((GSSException) result).getMajor() + " message" + ((GSSException) result).getMessage()); - - throw (GSSException) result; - } - - LOGGER.debug("KerberosHelper.initSecurityContext return " + ((byte[]) result).length + " bytes token"); - return (byte[]) result; } /** @@ -174,6 +199,18 @@ public class KerberosHelper { } } + /** + * Recreate client Kerberos context. + * + * @throws LoginException on error + */ + public static void clientReLogin() throws LoginException { + synchronized (LOCK) { + clientLoginContext = null; + clientLogin(); + } + } + /** * Create server side Kerberos login context for provided credentials. * diff --git a/src/java/davmail/http/SpNegoScheme.java b/src/java/davmail/http/SpNegoScheme.java index 65b109b5..b7701d12 100644 --- a/src/java/davmail/http/SpNegoScheme.java +++ b/src/java/davmail/http/SpNegoScheme.java @@ -187,11 +187,11 @@ public class SpNegoScheme implements AuthScheme { try { if (this.state == INITIATED || this.state == FAILED) { // send initial token to server - response = EncodingUtil.getAsciiString(Base64.encodeBase64(KerberosHelper.initSecurityContext(host, new byte[0]))); + response = EncodingUtil.getAsciiString(Base64.encodeBase64(KerberosHelper.initSecurityContext("HTTP", host, new byte[0]))); this.state = TYPE1_MSG_GENERATED; } else { // send challenge response - response = EncodingUtil.getAsciiString(Base64.encodeBase64(KerberosHelper.initSecurityContext(host, serverToken))); + response = EncodingUtil.getAsciiString(Base64.encodeBase64(KerberosHelper.initSecurityContext("HTTP", host, serverToken))); this.state = TYPE3_MSG_GENERATED; } } catch (GSSException gsse) {