From 9d0201edae4951ee1f63122b7e57161200a64bbc Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Feb 2011 16:10:12 -0500 Subject: [PATCH] Correctly verify when the user is authenticated or not. Handle "quasi-absolute" form targets during authentication. --- src/com/fsck/k9/mail/store/WebDavStore.java | 90 +++++++++++++++++---- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/src/com/fsck/k9/mail/store/WebDavStore.java b/src/com/fsck/k9/mail/store/WebDavStore.java index 8ef9c25cf..6950e6816 100644 --- a/src/com/fsck/k9/mail/store/WebDavStore.java +++ b/src/com/fsck/k9/mail/store/WebDavStore.java @@ -539,8 +539,7 @@ public class WebDavStore extends Store { info.requiredAuthType = AUTH_TYPE_BASIC; } else if ((info.statusCode >= 200 && info.statusCode < 300) || // Success (info.statusCode >= 300 && info.statusCode < 400) || // Redirect - (info.statusCode == 440)) // Unauthorized - + (info.statusCode == 440)) // Unauthorized { // We will handle all 3 situations the same. First we take an educated // guess at where the authorization DLL is located. If this is this @@ -588,7 +587,7 @@ public class WebDavStore extends Store { WebDavHttpClient httpClient = getHttpClient(); - String loginUrl = ""; + String loginUrl; if (info != null) { loginUrl = info.guessedAuthUrl; } else if (mCachedLoginUrl != null && !mCachedLoginUrl.equals("")) { @@ -614,13 +613,9 @@ public class WebDavStore extends Store { request.setEntity(formEntity); HttpResponse response = httpClient.executeOverride(request, mContext); - int statusCode = response.getStatusLine().getStatusCode(); - - if (statusCode >= 200 && statusCode < 300 && - mAuthCookies != null && !mAuthCookies.getCookies().isEmpty()) { - // Success, we're authenticated and cookies have been added to mAuthCookies for us. - } else { - // Check our response from the authentication URL above for a form action. + boolean authenticated = testAuthenticationResponse(response); + if (!authenticated) { + // Check the response from the authentication request above for a form action. String formAction = findFormAction(WebDavHttpClient.getUngzippedContent(response.getEntity())); if (formAction == null) { // If there is no form action, try using our redirect URL from the initial connection. @@ -644,11 +639,16 @@ public class WebDavStore extends Store { loginUrl = formAction; } else { // Append the form action to our current URL, minus the file name. - String urlPath = loginUri.getPath(); - int lastPathPos = urlPath.lastIndexOf('/'); - if (lastPathPos > -1) { - urlPath = urlPath.substring(0, lastPathPos + 1); - urlPath = urlPath.concat(formAction); + String urlPath; + if (formAction.startsWith("/")) { + urlPath = formAction; + } else { + urlPath = loginUri.getPath(); + int lastPathPos = urlPath.lastIndexOf('/'); + if (lastPathPos > -1) { + urlPath = urlPath.substring(0, lastPathPos + 1); + urlPath = urlPath.concat(formAction); + } } // Reconstruct the login URL based on the original login URL and the form action. @@ -666,7 +666,9 @@ public class WebDavStore extends Store { request = new HttpGeneric(loginUrl); request.setMethod("POST"); request.setEntity(formEntity); - httpClient.executeOverride(request, mContext); + + response = httpClient.executeOverride(request, mContext); + authenticated = testAuthenticationResponse(response); } catch (URISyntaxException e) { Log.e(K9.LOG_TAG, "URISyntaxException caught " + e + "\nTrace: " + processException(e)); throw new MessagingException("URISyntaxException caught", e); @@ -676,9 +678,11 @@ public class WebDavStore extends Store { } } - if (mAuthCookies != null && !mAuthCookies.getCookies().isEmpty()) { + if (authenticated) { mAuthentication = AUTH_TYPE_FORM_BASED; mCachedLoginUrl = loginUrl; + } else { + throw new MessagingException("Invalid credentials provided for authentication."); } } @@ -716,6 +720,58 @@ public class WebDavStore extends Store { return formAction; } + + private boolean testAuthenticationResponse(HttpResponse response) + throws MessagingException { + boolean authenticated = false; + int statusCode = response.getStatusLine().getStatusCode(); + + // Exchange 2007 will return a 302 status code no matter what. + if (((statusCode >= 200 && statusCode < 300) || statusCode == 302) && + mAuthCookies != null && !mAuthCookies.getCookies().isEmpty()) { + // We may be authenticated, we need to send a test request to know for sure. + // Exchange 2007 adds the same cookies whether the username and password were valid or not. + ConnectionInfo info = doInitialConnection(); + if (info.statusCode >= 200 && info.statusCode < 300) { + authenticated = true; + } else if (info.statusCode == 302) { + // If we are successfully authenticated, Exchange will try to redirect us to our OWA inbox. + // Otherwise, it will redirect us to a logon page. + // Our URL is in the form: https://hostname:port/Exchange/alias. + // The redirect is in the form: https://hostname:port/owa/alias. + // Do a simple replace and compare the resulting strings. + try { + String thisPath = new URI(mUrl).getPath(); + String redirectPath = new URI(info.redirectUrl).getPath(); + + if (!thisPath.endsWith("/")) { + thisPath = thisPath.concat("/"); + } + if (!redirectPath.endsWith("/")) { + redirectPath = redirectPath.concat("/"); + } + + if (redirectPath.equalsIgnoreCase(thisPath)) { + authenticated = true; + } else { + int found = thisPath.indexOf('/', 1); + if (found != -1) { + String replace = thisPath.substring(0, found + 1); + redirectPath = redirectPath.replace("/owa/", replace); + if (redirectPath.equalsIgnoreCase(thisPath)) { + authenticated = true; + } + } + } + } catch (URISyntaxException e) { + Log.e(K9.LOG_TAG, "URISyntaxException caught " + e + "\nTrace: " + processException(e)); + throw new MessagingException("URISyntaxException caught", e); + } + } + } + + return authenticated; + } public CookieStore getAuthCookies() { return mAuthCookies;