mirror of
https://github.com/moparisthebest/davmail
synced 2025-01-07 03:38:05 -05:00
Refactor form based authentication : parse html content with htmlcleaner-2.1
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@185 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
39d4bafb91
commit
932bc7468c
@ -18,6 +18,7 @@
|
|||||||
<classPath>dist\lib\saxpath-1.0-FCS.jar</classPath>
|
<classPath>dist\lib\saxpath-1.0-FCS.jar</classPath>
|
||||||
<classPath>dist\lib\slide-webdavlib-2.1.jar</classPath>
|
<classPath>dist\lib\slide-webdavlib-2.1.jar</classPath>
|
||||||
<classPath>dist\lib\swt-3.3-win32-x86.jar</classPath>
|
<classPath>dist\lib\swt-3.3-win32-x86.jar</classPath>
|
||||||
|
<classPath>dist\lib\htmlcleaner-2.1.jar</classPath>
|
||||||
<classPath>dist\davmail.jar</classPath>
|
<classPath>dist\davmail.jar</classPath>
|
||||||
<embeddedJar>false</embeddedJar>
|
<embeddedJar>false</embeddedJar>
|
||||||
<executableName>dist\davmail.exe</executableName>
|
<executableName>dist\davmail.exe</executableName>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<classPath>dist\lib\saxpath-1.0-FCS.jar</classPath>
|
<classPath>dist\lib\saxpath-1.0-FCS.jar</classPath>
|
||||||
<classPath>dist\lib\slide-webdavlib-2.1.jar</classPath>
|
<classPath>dist\lib\slide-webdavlib-2.1.jar</classPath>
|
||||||
<classPath>dist\lib\swt-3.3-win32-x86.jar</classPath>
|
<classPath>dist\lib\swt-3.3-win32-x86.jar</classPath>
|
||||||
|
<classPath>dist\lib\htmlcleaner-2.1.jar</classPath>
|
||||||
<classPath>dist\davmail.jar</classPath>
|
<classPath>dist\davmail.jar</classPath>
|
||||||
<embeddedJar>false</embeddedJar>
|
<embeddedJar>false</embeddedJar>
|
||||||
<executableName>dist\davmailconsole.exe</executableName>
|
<executableName>dist\davmailconsole.exe</executableName>
|
||||||
|
BIN
lib/htmlcleaner-2.1.jar
Normal file
BIN
lib/htmlcleaner-2.1.jar
Normal file
Binary file not shown.
5
pom.xml
5
pom.xml
@ -107,6 +107,11 @@
|
|||||||
<artifactId>servlet-api</artifactId>
|
<artifactId>servlet-api</artifactId>
|
||||||
<version>2.4</version>
|
<version>2.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>htmlcleaner</groupId>
|
||||||
|
<artifactId>htmlcleaner</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<sourceDirectory>src/java</sourceDirectory>
|
<sourceDirectory>src/java</sourceDirectory>
|
||||||
|
@ -13,6 +13,8 @@ import org.apache.webdav.lib.Property;
|
|||||||
import org.apache.webdav.lib.ResponseEntity;
|
import org.apache.webdav.lib.ResponseEntity;
|
||||||
import org.apache.webdav.lib.WebdavResource;
|
import org.apache.webdav.lib.WebdavResource;
|
||||||
import org.apache.webdav.lib.methods.SearchMethod;
|
import org.apache.webdav.lib.methods.SearchMethod;
|
||||||
|
import org.htmlcleaner.HtmlCleaner;
|
||||||
|
import org.htmlcleaner.TagNode;
|
||||||
|
|
||||||
import javax.mail.internet.MimeUtility;
|
import javax.mail.internet.MimeUtility;
|
||||||
import javax.xml.stream.XMLInputFactory;
|
import javax.xml.stream.XMLInputFactory;
|
||||||
@ -100,88 +102,73 @@ public class ExchangeSession {
|
|||||||
* Try to find logon method path from logon form body.
|
* Try to find logon method path from logon form body.
|
||||||
*
|
*
|
||||||
* @param initmethod form body http method
|
* @param initmethod form body http method
|
||||||
* @return logon method path
|
* @return logon method
|
||||||
*/
|
*/
|
||||||
protected String getLogonMethodPathAndBaseUrl(HttpMethod initmethod) {
|
protected PostMethod buildLogonMethod(HttpClient httpClient, HttpMethod initmethod) throws IOException {
|
||||||
// default logon method path
|
|
||||||
String logonMethodPath = "/exchweb/bin/auth/owaauth.dll";
|
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 {
|
try {
|
||||||
loginFormReader = new BufferedReader(new InputStreamReader(initmethod.getResponseBodyAsStream()));
|
TagNode node = cleaner.clean(initmethod.getResponseBodyAsStream());
|
||||||
String line;
|
List<TagNode> forms = node.getElementListByName("form", true);
|
||||||
// skip to form action
|
if (forms.size() == 1) {
|
||||||
final String FORM_ACTION = "<form action=\"";
|
TagNode form = forms.get(0);
|
||||||
final String DESTINATION_INPUT = "name=\"destination\" value=\"";
|
String logonMethodPath = form.getAttributeByName("action");
|
||||||
//noinspection StatementWithEmptyBody
|
|
||||||
while ((line = loginFormReader.readLine()) != null && line.toLowerCase().indexOf(FORM_ACTION) == -1) {
|
// allow relative URLs
|
||||||
}
|
if (!logonMethodPath.startsWith("/")) {
|
||||||
if (line != null) {
|
String path = initmethod.getPath();
|
||||||
int start = line.toLowerCase().indexOf(FORM_ACTION) + FORM_ACTION.length();
|
int end = path.lastIndexOf('/');
|
||||||
int end = line.indexOf("\"", start);
|
if (end >= 0) {
|
||||||
logonMethodPath = line.substring(start, end);
|
logonMethodPath = path.substring(0, end + 1) + logonMethodPath;
|
||||||
//noinspection StatementWithEmptyBody
|
}
|
||||||
while ((line = loginFormReader.readLine()) != null && line.indexOf(DESTINATION_INPUT) == -1) {
|
|
||||||
}
|
}
|
||||||
if (line != null) {
|
logonMethod = new PostMethod(logonMethodPath);
|
||||||
start = line.indexOf(DESTINATION_INPUT) + DESTINATION_INPUT.length();
|
|
||||||
end = line.indexOf("\"", start);
|
List<TagNode> inputList = form.getElementListByName("input", true);
|
||||||
baseUrl = line.substring(start, end);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// allow relative URLs
|
List<TagNode> frameList = node.getElementListByName("frame", true);
|
||||||
if (!logonMethodPath.startsWith("/")) {
|
if (frameList.size() == 1) {
|
||||||
String path = initmethod.getPath();
|
String src = frameList.get(0).getAttributeByName("src");
|
||||||
int end = path.lastIndexOf('/');
|
if (src != null) {
|
||||||
if (end >= 0) {
|
LOGGER.debug("Frames detected in form page, try frame content");
|
||||||
logonMethodPath = path.substring(0, end + 1) + logonMethodPath;
|
initmethod.releaseConnection();
|
||||||
|
HttpMethod newInitMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, src);
|
||||||
|
logonMethod = buildLogonMethod(httpClient, newInitMethod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.error("Error parsing login form at " + initmethod.getPath());
|
LOGGER.error("Error parsing login form at " + initmethod.getURI());
|
||||||
} finally {
|
} finally {
|
||||||
if (loginFormReader != null) {
|
|
||||||
try {
|
|
||||||
loginFormReader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.error("Error parsing login form at " + initmethod.getPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initmethod.releaseConnection();
|
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");
|
LOGGER.debug("Form based authentication detected");
|
||||||
// get logon method path and actual destination (baseUrl)
|
// build logon method with actual destination (baseUrl)
|
||||||
String logonMethodPath = getLogonMethodPathAndBaseUrl(initmethod);
|
HttpMethod logonMethod = buildLogonMethod(httpClient, initmethod);
|
||||||
|
((PostMethod) logonMethod).addParameter("username", userName);
|
||||||
PostMethod logonMethod = new PostMethod(
|
((PostMethod) logonMethod).addParameter("password", password);
|
||||||
logonMethodPath + "?ForcedBasic=false&Basic=false&Private=true&Language=No_Value"
|
logonMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, logonMethod);
|
||||||
);
|
return logonMethod;
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getMailPath(HttpMethod method) {
|
protected String getMailPath(HttpMethod method) {
|
||||||
@ -255,13 +242,13 @@ public class ExchangeSession {
|
|||||||
HttpMethod method = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, baseUrl);
|
HttpMethod method = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, baseUrl);
|
||||||
|
|
||||||
if (!isBasicAuthentication) {
|
if (!isBasicAuthentication) {
|
||||||
formLogin(httpClient, method, userName, password);
|
method = formLogin(httpClient, method, userName, password);
|
||||||
// reexecute method with new base URL
|
// 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
|
// User may be authenticated, get various session information
|
||||||
int status = method.getStatusCode();
|
|
||||||
if (status != HttpStatus.SC_OK) {
|
if (status != HttpStatus.SC_OK) {
|
||||||
HttpException ex = new HttpException();
|
HttpException ex = new HttpException();
|
||||||
ex.setReasonCode(status);
|
ex.setReasonCode(status);
|
||||||
@ -270,7 +257,7 @@ public class ExchangeSession {
|
|||||||
}
|
}
|
||||||
// test form based authentication
|
// test form based authentication
|
||||||
String queryString = method.getQueryString();
|
String queryString = method.getQueryString();
|
||||||
if (queryString != null && queryString.endsWith("reason=2")) {
|
if (queryString != null && queryString.contains("reason=2")) {
|
||||||
method.releaseConnection();
|
method.releaseConnection();
|
||||||
if (userName != null && userName.contains("\\")) {
|
if (userName != null && userName.contains("\\")) {
|
||||||
throw new HttpException("Authentication failed: invalid user or password");
|
throw new HttpException("Authentication failed: invalid user or password");
|
||||||
|
@ -121,8 +121,12 @@ public class DavGatewayHttpClientFacade {
|
|||||||
*/
|
*/
|
||||||
public static HttpMethod executeFollowRedirects(HttpClient httpClient, String url) throws IOException {
|
public static HttpMethod executeFollowRedirects(HttpClient httpClient, String url) throws IOException {
|
||||||
HttpMethod method = new GetMethod(url);
|
HttpMethod method = new GetMethod(url);
|
||||||
|
method.setFollowRedirects(false);
|
||||||
|
return executeFollowRedirects(httpClient, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpMethod executeFollowRedirects(HttpClient httpClient, HttpMethod method) throws IOException {
|
||||||
try {
|
try {
|
||||||
method.setFollowRedirects(false);
|
|
||||||
httpClient.executeMethod(method);
|
httpClient.executeMethod(method);
|
||||||
Header location = method.getResponseHeader("Location");
|
Header location = method.getResponseHeader("Location");
|
||||||
int redirectCount = 0;
|
int redirectCount = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user