mirror of
https://github.com/moparisthebest/davmail
synced 2025-01-05 10:47:59 -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\slide-webdavlib-2.1.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>
|
||||
<embeddedJar>false</embeddedJar>
|
||||
<executableName>dist\davmail.exe</executableName>
|
||||
|
@ -18,6 +18,7 @@
|
||||
<classPath>dist\lib\saxpath-1.0-FCS.jar</classPath>
|
||||
<classPath>dist\lib\slide-webdavlib-2.1.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>
|
||||
<embeddedJar>false</embeddedJar>
|
||||
<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>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>htmlcleaner</groupId>
|
||||
<artifactId>htmlcleaner</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<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.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 = "<form action=\"";
|
||||
final String DESTINATION_INPUT = "name=\"destination\" value=\"";
|
||||
//noinspection StatementWithEmptyBody
|
||||
while ((line = loginFormReader.readLine()) != null && line.toLowerCase().indexOf(FORM_ACTION) == -1) {
|
||||
}
|
||||
if (line != null) {
|
||||
int start = line.toLowerCase().indexOf(FORM_ACTION) + FORM_ACTION.length();
|
||||
int end = line.indexOf("\"", start);
|
||||
logonMethodPath = line.substring(start, end);
|
||||
//noinspection StatementWithEmptyBody
|
||||
while ((line = loginFormReader.readLine()) != null && line.indexOf(DESTINATION_INPUT) == -1) {
|
||||
TagNode node = cleaner.clean(initmethod.getResponseBodyAsStream());
|
||||
List<TagNode> 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<TagNode> 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<TagNode> 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");
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user