diff --git a/davmail.jsmooth b/davmail.jsmooth index 43118344..bc2fc2df 100644 --- a/davmail.jsmooth +++ b/davmail.jsmooth @@ -18,6 +18,7 @@ dist\lib\saxpath-1.0-FCS.jar dist\lib\slide-webdavlib-2.1.jar dist\lib\swt-3.3-win32-x86.jar +dist\lib\htmlcleaner-2.1.jar dist\davmail.jar false dist\davmail.exe diff --git a/davmailconsole.jsmooth b/davmailconsole.jsmooth index 2627683b..a747f260 100644 --- a/davmailconsole.jsmooth +++ b/davmailconsole.jsmooth @@ -18,6 +18,7 @@ dist\lib\saxpath-1.0-FCS.jar dist\lib\slide-webdavlib-2.1.jar dist\lib\swt-3.3-win32-x86.jar +dist\lib\htmlcleaner-2.1.jar dist\davmail.jar false dist\davmailconsole.exe diff --git a/lib/htmlcleaner-2.1.jar b/lib/htmlcleaner-2.1.jar new file mode 100644 index 00000000..ca14f056 Binary files /dev/null and b/lib/htmlcleaner-2.1.jar differ diff --git a/pom.xml b/pom.xml index ec9d00fe..d363d222 100644 --- a/pom.xml +++ b/pom.xml @@ -107,6 +107,11 @@ servlet-api 2.4 + + htmlcleaner + htmlcleaner + 2.1 + src/java diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 768594de..f28a0298 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -13,6 +13,8 @@ import org.apache.webdav.lib.Property; import org.apache.webdav.lib.ResponseEntity; import org.apache.webdav.lib.WebdavResource; import org.apache.webdav.lib.methods.SearchMethod; +import org.htmlcleaner.HtmlCleaner; +import org.htmlcleaner.TagNode; import javax.mail.internet.MimeUtility; import javax.xml.stream.XMLInputFactory; @@ -100,88 +102,73 @@ public class ExchangeSession { * Try to find logon method path from logon form body. * * @param initmethod form body http method - * @return logon method path + * @return logon method */ - protected String getLogonMethodPathAndBaseUrl(HttpMethod initmethod) { - // default logon method path - String logonMethodPath = "/exchweb/bin/auth/owaauth.dll"; + protected PostMethod buildLogonMethod(HttpClient httpClient, HttpMethod initmethod) throws IOException { + + PostMethod logonMethod = null; + + // create an instance of HtmlCleaner + HtmlCleaner cleaner = new HtmlCleaner(); - // try to parse login form to determine logon url and destination - BufferedReader loginFormReader = null; try { - loginFormReader = new BufferedReader(new InputStreamReader(initmethod.getResponseBodyAsStream())); - String line; - // skip to form action - final String FORM_ACTION = "
forms = node.getElementListByName("form", true); + if (forms.size() == 1) { + TagNode form = forms.get(0); + String logonMethodPath = form.getAttributeByName("action"); + + // allow relative URLs + if (!logonMethodPath.startsWith("/")) { + String path = initmethod.getPath(); + int end = path.lastIndexOf('/'); + if (end >= 0) { + logonMethodPath = path.substring(0, end + 1) + logonMethodPath; + } } - if (line != null) { - start = line.indexOf(DESTINATION_INPUT) + DESTINATION_INPUT.length(); - end = line.indexOf("\"", start); - baseUrl = line.substring(start, end); + logonMethod = new PostMethod(logonMethodPath); + + List inputList = form.getElementListByName("input", true); + for (TagNode input : inputList) { + String type = input.getAttributeByName("type"); + String name = input.getAttributeByName("name"); + String value = input.getAttributeByName("value"); + if ("hidden".equalsIgnoreCase(type) && name != null && value != null) { + logonMethod.addParameter(name, value); + } } - } - // allow relative URLs - if (!logonMethodPath.startsWith("/")) { - String path = initmethod.getPath(); - int end = path.lastIndexOf('/'); - if (end >= 0) { - logonMethodPath = path.substring(0, end + 1) + logonMethodPath; + } else { + List frameList = node.getElementListByName("frame", true); + if (frameList.size() == 1) { + String src = frameList.get(0).getAttributeByName("src"); + if (src != null) { + LOGGER.debug("Frames detected in form page, try frame content"); + initmethod.releaseConnection(); + HttpMethod newInitMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, src); + logonMethod = buildLogonMethod(httpClient, newInitMethod); + } } } } catch (IOException e) { - LOGGER.error("Error parsing login form at " + initmethod.getPath()); + LOGGER.error("Error parsing login form at " + initmethod.getURI()); } finally { - if (loginFormReader != null) { - try { - loginFormReader.close(); - } catch (IOException e) { - LOGGER.error("Error parsing login form at " + initmethod.getPath()); - } - } initmethod.releaseConnection(); } - return logonMethodPath; + + if (logonMethod == null) { + throw new IOException("Authentication form not found at " + initmethod.getURI() + ", retry with " + initmethod.getURI() + "exchange"); + } + return logonMethod; } - protected void formLogin(HttpClient httpClient, HttpMethod initmethod, String userName, String password) throws IOException { + protected HttpMethod formLogin(HttpClient httpClient, HttpMethod initmethod, String userName, String password) throws IOException { LOGGER.debug("Form based authentication detected"); - // get logon method path and actual destination (baseUrl) - String logonMethodPath = getLogonMethodPathAndBaseUrl(initmethod); - - PostMethod logonMethod = new PostMethod( - logonMethodPath + "?ForcedBasic=false&Basic=false&Private=true&Language=No_Value" - ); - logonMethod.addParameter("destination", baseUrl); - logonMethod.addParameter("flags", "4"); -// logonMethod.addParameter("visusername", userName.substring(userName.lastIndexOf('\\'))); - logonMethod.addParameter("username", userName); - logonMethod.addParameter("password", password); -// logonMethod.addParameter("SubmitCreds", "Log On"); -// logonMethod.addParameter("forcedownlevel", "0"); - logonMethod.addParameter("trusted", "4"); - - try { - httpClient.executeMethod(logonMethod); - } finally { - logonMethod.releaseConnection(); - } - Header locationHeader = logonMethod.getResponseHeader("Location"); - - if (logonMethod.getStatusCode() != HttpURLConnection.HTTP_MOVED_TEMP || - locationHeader == null || - !baseUrl.equals(locationHeader.getValue())) { - throw new HttpException("Authentication failed"); - } + // build logon method with actual destination (baseUrl) + HttpMethod logonMethod = buildLogonMethod(httpClient, initmethod); + ((PostMethod) logonMethod).addParameter("username", userName); + ((PostMethod) logonMethod).addParameter("password", password); + logonMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, logonMethod); + return logonMethod; } protected String getMailPath(HttpMethod method) { @@ -255,13 +242,13 @@ public class ExchangeSession { HttpMethod method = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, baseUrl); if (!isBasicAuthentication) { - formLogin(httpClient, method, userName, password); + method = formLogin(httpClient, method, userName, password); // reexecute method with new base URL - method = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, baseUrl); +// method = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, baseUrl); } + int status = method.getStatusCode(); // User may be authenticated, get various session information - int status = method.getStatusCode(); if (status != HttpStatus.SC_OK) { HttpException ex = new HttpException(); ex.setReasonCode(status); @@ -270,7 +257,7 @@ public class ExchangeSession { } // test form based authentication String queryString = method.getQueryString(); - if (queryString != null && queryString.endsWith("reason=2")) { + if (queryString != null && queryString.contains("reason=2")) { method.releaseConnection(); if (userName != null && userName.contains("\\")) { throw new HttpException("Authentication failed: invalid user or password"); diff --git a/src/java/davmail/http/DavGatewayHttpClientFacade.java b/src/java/davmail/http/DavGatewayHttpClientFacade.java index af523dee..e7a8099a 100644 --- a/src/java/davmail/http/DavGatewayHttpClientFacade.java +++ b/src/java/davmail/http/DavGatewayHttpClientFacade.java @@ -121,8 +121,12 @@ public class DavGatewayHttpClientFacade { */ public static HttpMethod executeFollowRedirects(HttpClient httpClient, String url) throws IOException { HttpMethod method = new GetMethod(url); + method.setFollowRedirects(false); + return executeFollowRedirects(httpClient, method); + } + + public static HttpMethod executeFollowRedirects(HttpClient httpClient, HttpMethod method) throws IOException { try { - method.setFollowRedirects(false); httpClient.executeMethod(method); Header location = method.getResponseHeader("Location"); int redirectCount = 0;