From 383447671067b62d805ef85d41e5b6acdafed1a4 Mon Sep 17 00:00:00 2001 From: mguessan Date: Tue, 12 May 2009 23:14:36 +0000 Subject: [PATCH] Patch 2790299 by Mitchell V. Oliver: Add support for SSL to client connections git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@561 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- src/java/davmail/AbstractServer.java | 61 +++++++++++++++++++++++--- src/java/davmail/DavGateway.java | 5 ++- src/java/davmail/Settings.java | 4 ++ src/java/davmail/ui/SettingsFrame.java | 59 +++++++++++++++++++++---- src/java/davmailmessages.properties | 11 +++++ src/java/davmailmessages_fr.properties | 17 +++++-- 6 files changed, 137 insertions(+), 20 deletions(-) diff --git a/src/java/davmail/AbstractServer.java b/src/java/davmail/AbstractServer.java index af775c5f..57c4c539 100644 --- a/src/java/davmail/AbstractServer.java +++ b/src/java/davmail/AbstractServer.java @@ -1,11 +1,18 @@ package davmail; +import davmail.exception.DavMailException; import davmail.ui.tray.DavGatewayTray; +import javax.net.ServerSocketFactory; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import java.io.FileInputStream; import java.io.IOException; import java.net.Inet4Address; import java.net.ServerSocket; import java.net.Socket; +import java.security.GeneralSecurityException; +import java.security.KeyStore; /** * Generic abstract server common to SMTP and POP3 implementations @@ -15,6 +22,7 @@ public abstract class AbstractServer extends Thread { private ServerSocket serverSocket; public abstract String getProtocolName(); + /** * Server socket TCP port * @@ -43,15 +51,55 @@ public abstract class AbstractServer extends Thread { /** * Bind server socket on defined port. - * @throws IOException unable to create server socket + * + * @throws DavMailException unable to create server socket */ - public void bind() throws IOException { + public void bind() throws DavMailException { String bindAddress = Settings.getProperty("davmail.bindAddress"); - //noinspection SocketOpenedButNotSafelyClosed - if (bindAddress == null || bindAddress.length() == 0) { - serverSocket = new ServerSocket(this.port); + String keystoreFile = Settings.getProperty("davmail.ssl.keystoreFile"); + + ServerSocketFactory serverSocketFactory; + if (keystoreFile == null || keystoreFile.length() == 0) { + serverSocketFactory = ServerSocketFactory.getDefault(); } else { - serverSocket = new ServerSocket(this.port, 0, Inet4Address.getByName(bindAddress)); + + try { + // keystore for keys and certificates + // keystore and private keys should be password protected... + KeyStore keystore = KeyStore.getInstance(Settings.getProperty("davmail.ssl.keystoreType")); + keystore.load(new FileInputStream(keystoreFile), + Settings.getProperty("davmail.ssl.keystorePass").toCharArray()); + + // KeyManagerFactory to create key managers + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + + // initialize KMF to work with keystore + kmf.init(keystore, Settings.getProperty("davmail.ssl.keyPass").toCharArray()); + + // SSLContext is environment for implementing JSSE... + // create ServerSocketFactory + SSLContext sslc = SSLContext.getInstance("SSLv3"); + + // initialize sslc to work with key managers + sslc.init(kmf.getKeyManagers(), null, null); + + // create ServerSocketFactory from sslc + serverSocketFactory = sslc.getServerSocketFactory(); + } catch (IOException ex) { + throw new DavMailException("LOG_EXCEPTION_CREATING_SSL_SERVER_SOCKET", getProtocolName(), port, ex.getMessage() == null ? ex.toString() : ex.getMessage()); + } catch (GeneralSecurityException ex) { + throw new DavMailException("LOG_EXCEPTION_CREATING_SSL_SERVER_SOCKET", getProtocolName(), port, ex.getMessage() == null ? ex.toString() : ex.getMessage()); + } + } + try { + // create the server socket + if (bindAddress == null || bindAddress.length() == 0) { + serverSocket = serverSocketFactory.createServerSocket(port); + } else { + serverSocket = serverSocketFactory.createServerSocket(port, 0, Inet4Address.getByName(bindAddress)); + } + } catch (IOException e) { + throw new DavMailException("LOG_SOCKET_BIND_FAILED", getProtocolName(), port); } } @@ -114,4 +162,3 @@ public abstract class AbstractServer extends Thread { } } } - diff --git a/src/java/davmail/DavGateway.java b/src/java/davmail/DavGateway.java index 13aa514a..00926b71 100644 --- a/src/java/davmail/DavGateway.java +++ b/src/java/davmail/DavGateway.java @@ -9,6 +9,7 @@ import davmail.ldap.LdapServer; import davmail.pop.PopServer; import davmail.smtp.SmtpServer; import davmail.ui.tray.DavGatewayTray; +import davmail.exception.DavMailException; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; @@ -108,8 +109,8 @@ public class DavGateway { server.bind(); server.start(); messages.add(new BundleMessage("LOG_PROTOCOL_PORT", server.getProtocolName(), server.getPort())); - } catch (BindException e) { - errorMessages.add(new BundleMessage("LOG_SOCKET_BIND_FAILED", server.getProtocolName(), server.getPort())); + } catch (DavMailException e) { + errorMessages.add(e.getBundleMessage()); } catch (IOException e) { errorMessages.add(new BundleMessage("LOG_SOCKET_BIND_FAILED", server.getProtocolName(), server.getPort())); } diff --git a/src/java/davmail/Settings.java b/src/java/davmail/Settings.java index 6106b4d4..37d0a085 100644 --- a/src/java/davmail/Settings.java +++ b/src/java/davmail/Settings.java @@ -65,6 +65,10 @@ public class Settings { SETTINGS.put("davmail.proxyPassword", ""); SETTINGS.put("davmail.server", Boolean.FALSE.toString()); SETTINGS.put("davmail.server.certificate.hash", ""); + SETTINGS.put("davmail.ssl.keystoreType", ""); + SETTINGS.put("davmail.ssl.keystoreFile", ""); + SETTINGS.put("davmail.ssl.keystorePass", ""); + SETTINGS.put("davmail.ssl.keyPass", ""); // logging SETTINGS.put("log4j.rootLogger", Priority.WARN.toString()); diff --git a/src/java/davmail/ui/SettingsFrame.java b/src/java/davmail/ui/SettingsFrame.java index ce8efaeb..53e0c142 100644 --- a/src/java/davmail/ui/SettingsFrame.java +++ b/src/java/davmail/ui/SettingsFrame.java @@ -1,8 +1,8 @@ package davmail.ui; +import davmail.BundleMessage; import davmail.DavGateway; import davmail.Settings; -import davmail.BundleMessage; import davmail.ui.tray.DavGatewayTray; import org.apache.log4j.Level; @@ -43,6 +43,11 @@ public class SettingsFrame extends JFrame { JTextField certHashField; JCheckBox disableUpdateCheck; + JComboBox keystoreTypeCombo; + JTextField keystoreFileField; + JPasswordField keystorePassField; + JPasswordField keyPassField; + JComboBox rootLoggingLevelField; JComboBox davmailLoggingLevelField; JComboBox httpclientLoggingLevelField; @@ -206,6 +211,28 @@ public class SettingsFrame extends JFrame { return proxyPanel; } + protected JPanel getEncryptionPanel() { + JPanel encryptionPanel = new JPanel(new GridLayout(4, 2)); + encryptionPanel.setBorder(BorderFactory.createTitledBorder(BundleMessage.format("UI_CERTIFICATE"))); + + keystoreTypeCombo = new JComboBox(new String[]{"JKS", "PKCS12"}); + keystoreTypeCombo.setSelectedItem(Settings.getProperty("davmail.ssl.keystoreType")); + keystoreFileField = new JTextField(Settings.getProperty("davmail.ssl.keystoreFile"), 15); + keystorePassField = new JPasswordField(Settings.getProperty("davmail.ssl.keystorePass"), 15); + keyPassField = new JPasswordField(Settings.getProperty("davmail.ssl.keyPass"), 15); + + addSettingComponent(encryptionPanel, BundleMessage.format("UI_KEY_STORE_TYPE"), keystoreTypeCombo, + BundleMessage.format("UI_KEY_STORE_TYPE_HELP")); + addSettingComponent(encryptionPanel, BundleMessage.format("UI_KEY_STORE"), keystoreFileField, + BundleMessage.format("UI_KEY_STORE_HELP")); + addSettingComponent(encryptionPanel, BundleMessage.format("UI_KEY_STORE_PASSWORD"), keystorePassField, + BundleMessage.format("UI_KEY_STORE_PASSWORD_HELP")); + addSettingComponent(encryptionPanel, BundleMessage.format("UI_KEY_PASSWORD"), keyPassField, + BundleMessage.format("UI_KEY_PASSWORD_HELP")); + + return encryptionPanel; + } + public JPanel getNetworkSettingsPanel() { JPanel networkSettingsPanel = new JPanel(new GridLayout(4, 2)); networkSettingsPanel.setBorder(BorderFactory.createTitledBorder(BundleMessage.format("UI_NETWORK"))); @@ -285,6 +312,11 @@ public class SettingsFrame extends JFrame { certHashField.setText(Settings.getProperty("davmail.server.certificate.hash")); disableUpdateCheck.setSelected(Settings.getBooleanProperty(("davmail.disableUpdateCheck"))); + keystoreTypeCombo.setSelectedItem(Settings.getProperty("davmail.ssl.keystoreType")); + keystoreFileField.setText(Settings.getProperty("davmail.ssl.keystoreFile")); + keystorePassField.setText(Settings.getProperty("davmail.ssl.keystorePass")); + keyPassField.setText(Settings.getProperty("davmail.ssl.keyPass")); + rootLoggingLevelField.setSelectedItem(Settings.getLoggingLevel("rootLogger")); davmailLoggingLevelField.setSelectedItem(Settings.getLoggingLevel("davmail")); httpclientLoggingLevelField.setSelectedItem(Settings.getLoggingLevel("org.apache.commons.httpclient")); @@ -324,6 +356,13 @@ public class SettingsFrame extends JFrame { proxyPanel.add(new JPanel()); tabbedPane.add(BundleMessage.format("UI_TAB_PROXY"), proxyPanel); + JPanel encryptionPanel = new JPanel(); + encryptionPanel.setLayout(new BoxLayout(encryptionPanel, BoxLayout.Y_AXIS)); + encryptionPanel.add(getEncryptionPanel()); + // empty panel + encryptionPanel.add(new JPanel()); + tabbedPane.add(BundleMessage.format("UI_TAB_ENCRYPTION"), encryptionPanel); + advancedPanel.add(getNetworkSettingsPanel()); advancedPanel.add(getLoggingSettingsPanel()); @@ -339,11 +378,11 @@ public class SettingsFrame extends JFrame { public void actionPerformed(ActionEvent evt) { // save options Settings.setProperty("davmail.url", urlField.getText()); - Settings.setProperty("davmail.popPort", popPortCheckBox.isSelected()?popPortField.getText():""); - Settings.setProperty("davmail.imapPort", imapPortCheckBox.isSelected()?imapPortField.getText():""); - Settings.setProperty("davmail.smtpPort", smtpPortCheckBox.isSelected()?smtpPortField.getText():""); - Settings.setProperty("davmail.caldavPort", caldavPortCheckBox.isSelected()?caldavPortField.getText():""); - Settings.setProperty("davmail.ldapPort", ldapPortCheckBox.isSelected()?ldapPortField.getText():""); + Settings.setProperty("davmail.popPort", popPortCheckBox.isSelected() ? popPortField.getText() : ""); + Settings.setProperty("davmail.imapPort", imapPortCheckBox.isSelected() ? imapPortField.getText() : ""); + Settings.setProperty("davmail.smtpPort", smtpPortCheckBox.isSelected() ? smtpPortField.getText() : ""); + Settings.setProperty("davmail.caldavPort", caldavPortCheckBox.isSelected() ? caldavPortField.getText() : ""); + Settings.setProperty("davmail.ldapPort", ldapPortCheckBox.isSelected() ? ldapPortField.getText() : ""); Settings.setProperty("davmail.keepDelay", keepDelayField.getText()); Settings.setProperty("davmail.sentKeepDelay", sentKeepDelayField.getText()); Settings.setProperty("davmail.caldavPastDelay", caldavPastDelayField.getText()); @@ -357,6 +396,10 @@ public class SettingsFrame extends JFrame { Settings.setProperty("davmail.allowRemote", String.valueOf(allowRemoteField.isSelected())); Settings.setProperty("davmail.server.certificate.hash", certHashField.getText()); Settings.setProperty("davmail.disableUpdateCheck", String.valueOf(disableUpdateCheck.isSelected())); + Settings.setProperty("davmail.ssl.keystoreType", (String) keystoreTypeCombo.getSelectedItem()); + Settings.setProperty("davmail.ssl.keystoreFile", keystoreFileField.getText()); + Settings.setProperty("davmail.ssl.keystorePass", String.valueOf(keystorePassField.getPassword())); + Settings.setProperty("davmail.ssl.keyPass", String.valueOf(keyPassField.getPassword())); Settings.setLoggingLevel("rootLogger", (Level) rootLoggingLevelField.getSelectedItem()); Settings.setLoggingLevel("davmail", (Level) davmailLoggingLevelField.getSelectedItem()); @@ -381,8 +424,8 @@ public class SettingsFrame extends JFrame { help.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - DesktopBrowser.browse("http://davmail.sourceforge.net"); - } + DesktopBrowser.browse("http://davmail.sourceforge.net"); + } }); buttonPanel.add(ok); diff --git a/src/java/davmailmessages.properties b/src/java/davmailmessages.properties index 450f7cfb..91865157 100644 --- a/src/java/davmailmessages.properties +++ b/src/java/davmailmessages.properties @@ -20,6 +20,7 @@ LOG_EXCEPTION_GETTING_SOCKET_STREAMS=Exception while getting socket streams LOG_EXCEPTION_LISTENING_FOR_CONNECTIONS=Exception while listening for connections LOG_EXCEPTION_SENDING_ERROR_TO_CLIENT=Exception sending error to client LOG_EXCEPTION_WAITING_SERVER_THREAD_DIE=Exception waiting for server thread to die +LOG_EXCEPTION_CREATING_SSL_SERVER_SOCKET=Unable to bind server socket for {0} on port {1,number,#}: Exception creating secured server socket : {2} LOG_EXECUTE_FOLLOW_REDIRECTS=executeFollowRedirects({0}) LOG_EXECUTE_FOLLOW_REDIRECTS_COUNT=executeFollowRedirects: {0} redirectCount:{1} LOG_EXTERNAL_CONNECTION_REFUSED=Connection from external client refused @@ -205,3 +206,13 @@ EXCEPTION_EXCHANGE_LOGIN_FAILED=Exchange login exception: {0} UI_LAST_MESSAGE=Last message UI_LAST_LOG=Last log LOG_STARTING_DAVMAIL=Starting DavMail Gateway... +UI_KEY_STORE_TYPE=Key store type: +UI_KEY_STORE_TYPE_HELP=Choose key store type +UI_KEY_STORE=Key store: +UI_KEY_STORE_PASSWORD=Key store password: +UI_KEY_PASSWORD=Key password: +UI_KEY_STORE_HELP=SSL certificate key store file path +UI_KEY_STORE_PASSWORD_HELP=Key store password +UI_KEY_PASSWORD_HELP=SSL key password inside key store +UI_TAB_ENCRYPTION=Encryption +UI_CERTIFICATE=Certificate \ No newline at end of file diff --git a/src/java/davmailmessages_fr.properties b/src/java/davmailmessages_fr.properties index db9309a8..1ae47d43 100644 --- a/src/java/davmailmessages_fr.properties +++ b/src/java/davmailmessages_fr.properties @@ -89,7 +89,7 @@ UI_ABOUT=A propos... UI_ABOUT_DAVMAIL=A propos de la Passerelle DavMail UI_ABOUT_DAVMAIL_AUTHOR=Passerelle DavMail
Par Mickaël Guessant

UI_ACCEPT_CERTIFICATE=DavMail : Accepter le certificat ? -UI_ALLOW_REMOTE_CONNECTION=Autoriser les connexions distantes : +UI_ALLOW_REMOTE_CONNECTION=Autoriser connexions distantes : UI_ALLOW_REMOTE_CONNECTION_HELP=Autoriser les connexions distantes à la passerelle (mode serveur) UI_ANSWER_NO=n UI_ANSWER_YES=o @@ -121,7 +121,7 @@ UI_IMAP_PORT=Port IMAP local : UI_IMAP_PORT_HELP=Port IMAP local à configurer dans le client de messagerie UI_ISSUED_BY=Emis par UI_ISSUED_TO=Emis pour -UI_KEEP_DELAY=Délai de rétention dans la corbeille : +UI_KEEP_DELAY=Délai de rétention corbeille : UI_KEEP_DELAY_HELP=Nombre de jours de conservation des messages dans la corbeille UI_LATEST_VERSION=Dernière version disponible : {0}
Une nouvelle version de la Passerelle DavMail est disponible.
Télécharcher la dernière version
UI_LDAP_PORT=Port LDAP local : @@ -204,4 +204,15 @@ EXCEPTION_CONNECTION_FAILED=Connection OWA EXCEPTION_EXCHANGE_LOGIN_FAILED=Exception lors de la connexion Exchange : {0} LOG_STARTING_DAVMAIL=Démarrage de la passerelle DavMail... UI_LAST_LOG=Dernière trace -UI_LAST_MESSAGE=Dernier message \ No newline at end of file +UI_LAST_MESSAGE=Dernier message +LOG_EXCEPTION_CREATING_SSL_SERVER_SOCKET=Impossible d''ouvrir le port d''écoute {1,number,#} pour {0} : Erreur lors de la création du port d''écoute serveur sécurisé : {2} +UI_KEY_PASSWORD=Mot de passe clé : +UI_KEY_PASSWORD_HELP=Mot de passe clé SSL contenue dans le fichier des clés +UI_KEY_STORE=Fichier clés : +UI_KEY_STORE_HELP=Chemin du fichier contenant les clés et certificats SSL +UI_KEY_STORE_PASSWORD=Mot de passe fichier clés : +UI_KEY_STORE_PASSWORD_HELP=Mot de passe du fichier des clés +UI_KEY_STORE_TYPE=Type de fichier clés : +UI_KEY_STORE_TYPE_HELP=Choix du type de fichier de clés +UI_TAB_ENCRYPTION=Chiffrement +UI_CERTIFICATE=Certificat \ No newline at end of file