Experimental OTP (token) based authentication

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@848 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2009-11-23 09:53:04 +00:00
parent db0be1fe86
commit a01b996220
5 changed files with 77 additions and 5 deletions

View File

@ -24,6 +24,7 @@ import davmail.util.StringUtil;
import davmail.exception.DavMailAuthenticationException;
import davmail.exception.DavMailException;
import davmail.http.DavGatewayHttpClientFacade;
import davmail.http.DavGatewayOTPPrompt;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
@ -70,6 +71,25 @@ public class ExchangeSession {
*/
public static final SimpleTimeZone GMT_TIMEZONE = new SimpleTimeZone(0, "GMT");
protected static final Set<String> USER_NAME_FIELDS = new HashSet<String>();
static {
USER_NAME_FIELDS.add("username");
USER_NAME_FIELDS.add("txtUserName");
USER_NAME_FIELDS.add("userid");
USER_NAME_FIELDS.add("SafeWordUser");
}
protected static final Set<String> PASSWORD_FIELDS = new HashSet<String>();
static {
PASSWORD_FIELDS.add("password");
PASSWORD_FIELDS.add("txtUserPass");
PASSWORD_FIELDS.add("pw");
PASSWORD_FIELDS.add("basicPassword");
}
protected static final Set<String> TOKEN_FIELDS = new HashSet<String>();
static {
TOKEN_FIELDS.add("SafeWordPassword");
}
protected static final int FREE_BUSY_INTERVAL = 15;
protected static final Namespace URN_SCHEMAS_HTTPMAIL = Namespace.getNamespace("urn:schemas:httpmail:");
@ -367,14 +387,17 @@ public class ExchangeSession {
logonMethod.addParameter(name, value);
}
// custom login form
if ("txtUserName".equals(name) || "userid".equals(name)) {
if (USER_NAME_FIELDS.contains(name)) {
userNameInput = name;
} else if ("txtUserPass".equals(name) || "pw".equals(name)) {
} else if (PASSWORD_FIELDS.contains(name)) {
passwordInput = name;
} else if ("addr".equals(name)) {
// this is not a logon form but a redirect form
HttpMethod newInitMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, logonMethod);
logonMethod = buildLogonMethod(httpClient, newInitMethod);
} else if (TOKEN_FIELDS.contains(name)) {
// one time password, ask user
logonMethod.addParameter(name, DavGatewayOTPPrompt.getOneTimePassword());
}
}
} else {
@ -448,6 +471,10 @@ public class ExchangeSession {
// if logonMethod is not null, try to follow redirection
logonMethod = DavGatewayHttpClientFacade.executeFollowRedirects(httpClient, logonMethod);
checkFormLoginQueryString(logonMethod);
// also check cookies
if (!isAuthenticated()) {
throwAuthenticationFailed();
}
} else {
// authentication failed
throwAuthenticationFailed();

View File

@ -0,0 +1,39 @@
/*
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
* Copyright (C) 2009 Mickael Guessant
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package davmail.http;
import davmail.BundleMessage;
import davmail.ui.PasswordPromptDialog;
/**
* Ask user one time password.
*/
public class DavGatewayOTPPrompt {
private DavGatewayOTPPrompt() {
}
/**
* Ask user token password
* @return user provided one time password
*/
public static String getOneTimePassword() {
PasswordPromptDialog passwordPromptDialog = new PasswordPromptDialog(BundleMessage.format("UI_OTP_PASSWORD_PROMPT"));
return String.valueOf(passwordPromptDialog.getPassword());
}
}

View File

@ -39,7 +39,11 @@ public class PasswordPromptDialog extends JDialog {
* @return user password as char array
*/
public char[] getPassword() {
return password.clone();
if (password != null) {
return password.clone();
} else {
return "".toCharArray();
}
}
/**

View File

@ -230,4 +230,5 @@ LOG_EXCEPTION_CLOSING_KEYSTORE_INPUT_STREAM=Exception closing keystore input str
LOG_SUBFOLDER_ACCESS_FORBIDDEN=Subfolder access forbidden to {0}
LOG_FOLDER_NOT_FOUND=Folder {0} not found
LOG_FOLDER_ACCESS_FORBIDDEN=Folder access to {0} forbidden
LOG_FOLDER_ACCESS_ERROR=Folder access to {0} error: {1}
LOG_FOLDER_ACCESS_ERROR=Folder access to {0} error: {1}
UI_OTP_PASSWORD_PROMPT=One Time (token) Password:

View File

@ -230,4 +230,5 @@ LOG_EXCEPTION_CLOSING_KEYSTORE_INPUT_STREAM=Erreur
LOG_SUBFOLDER_ACCESS_FORBIDDEN=Accès interdit au sous dossiers de {0}
LOG_FOLDER_ACCESS_FORBIDDEN=Accès interdit au dossier {0}
LOG_FOLDER_NOT_FOUND=Dossier {0} introuvable
LOG_FOLDER_ACCESS_ERROR=Erreur lors de l''accès au dossier {0} : {1}
LOG_FOLDER_ACCESS_ERROR=Erreur lors de l''accès au dossier {0} : {1}
UI_OTP_PASSWORD_PROMPT=Mot de passe du jeton :