diff --git a/pom.xml b/pom.xml index 499be379..eda9f9a5 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,13 @@ Java Contributor + + Jeremiah Albrant + http://sourceforge.net/users/?user_id=2903536 + + Java Contributor + + Henning Holtschneider hehol@users.sourceforge.net @@ -225,7 +232,7 @@ org.eclipse swt - 3.6.0 + 3.7.0 true diff --git a/src/java/davmail/http/DavGatewaySSLProtocolSocketFactory.java b/src/java/davmail/http/DavGatewaySSLProtocolSocketFactory.java index b5f7bc7e..6aa0ab79 100644 --- a/src/java/davmail/http/DavGatewaySSLProtocolSocketFactory.java +++ b/src/java/davmail/http/DavGatewaySSLProtocolSocketFactory.java @@ -1,216 +1,226 @@ -/* - * 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.Settings; -import davmail.ui.PasswordPromptDialog; -import davmail.ui.tray.DavGatewayTray; -import org.apache.commons.httpclient.HttpsURL; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.Protocol; -import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; - -import javax.net.ssl.*; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.Socket; -import java.net.URL; -import java.security.*; -import java.util.ArrayList; - -/** - * Manual Socket Factory. - * Let user choose to accept or reject certificate - */ -public class DavGatewaySSLProtocolSocketFactory implements SecureProtocolSocketFactory { - /** - * Register custom Socket Factory to let user accept or reject certificate - */ - public static void register() { - String urlString = Settings.getProperty("davmail.url"); - try { - URL url = new URL(urlString); - String protocol = url.getProtocol(); - if ("https".equals(protocol)) { - int port = url.getPort(); - if (port < 0) { - port = HttpsURL.DEFAULT_PORT; - } - Protocol.registerProtocol(url.getProtocol(), - new Protocol(protocol, (ProtocolSocketFactory) new DavGatewaySSLProtocolSocketFactory(), port)); - } - } catch (MalformedURLException e) { - DavGatewayTray.error(new BundleMessage("LOG_INVALID_URL", urlString)); - } - } - - private KeyStore.ProtectionParameter getProtectionParameter(String password) { - if (password != null && password.length() > 0) { - // password provided: create a PasswordProtection - return new KeyStore.PasswordProtection(password.toCharArray()); - } else { - // request password at runtime through a callback - return new KeyStore.CallbackHandlerProtection(new CallbackHandler() { - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - if (callbacks.length > 0 && callbacks[0] instanceof PasswordCallback) { - PasswordPromptDialog passwordPromptDialog = new PasswordPromptDialog(((PasswordCallback) callbacks[0]).getPrompt()); - ((PasswordCallback) callbacks[0]).setPassword(passwordPromptDialog.getPassword()); - } - } - }); - } - } - - private SSLContext sslcontext; - - private SSLContext createSSLContext() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyManagementException, KeyStoreException { - // PKCS11 client certificate settings - String pkcs11Library = Settings.getProperty("davmail.ssl.pkcs11Library"); - - String clientKeystoreType = Settings.getProperty("davmail.ssl.clientKeystoreType"); - // set default keystore type - if (clientKeystoreType == null || clientKeystoreType.length() == 0) { - clientKeystoreType = "PKCS11"; - } - - if (pkcs11Library != null && pkcs11Library.length() > 0 && "PKCS11".equals(clientKeystoreType)) { - StringBuilder pkcs11Buffer = new StringBuilder(); - pkcs11Buffer.append("name=DavMail\n"); - pkcs11Buffer.append("library=").append(pkcs11Library).append('\n'); - String pkcs11Config = Settings.getProperty("davmail.ssl.pkcs11Config"); - if (pkcs11Config != null && pkcs11Config.length() > 0) { - pkcs11Buffer.append(pkcs11Config).append('\n'); - } - SunPKCS11ProviderHandler.registerProvider(pkcs11Buffer.toString()); - } - - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(/*KeyManagerFactory.getDefaultAlgorithm()*/"NewSunX509"); - - ArrayList keyStoreBuilders = new ArrayList(); - // PKCS11 (smartcard) keystore with password callback - KeyStore.Builder scBuilder = KeyStore.Builder.newInstance("PKCS11", null, getProtectionParameter(null)); - keyStoreBuilders.add(scBuilder); - - String clientKeystoreFile = Settings.getProperty("davmail.ssl.clientKeystoreFile"); - String clientKeystorePass = Settings.getProperty("davmail.ssl.clientKeystorePass"); - if (clientKeystoreFile != null && clientKeystoreFile.length() > 0 - && ("PKCS12".equals(clientKeystoreType) || "JKS".equals(clientKeystoreType))) { - // PKCS12 file based keystore - KeyStore.Builder fsBuilder = KeyStore.Builder.newInstance(clientKeystoreType, null, - new File(clientKeystoreFile), getProtectionParameter(clientKeystorePass)); - keyStoreBuilders.add(fsBuilder); - } - - ManagerFactoryParameters keyStoreBuilderParameters = new KeyStoreBuilderParameters(keyStoreBuilders); - keyManagerFactory.init(keyStoreBuilderParameters); - - SSLContext context = SSLContext.getInstance("SSL"); - context.init(keyManagerFactory.getKeyManagers(), new TrustManager[]{new DavGatewayX509TrustManager()}, null); - return context; - } - - private SSLContext getSSLContext() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, InvalidAlgorithmParameterException { - if (this.sslcontext == null) { - this.sslcontext = createSSLContext(); - } - return this.sslcontext; - } - - - public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException { - try { - return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); - } catch (NoSuchAlgorithmException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyManagementException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyStoreException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (InvalidAlgorithmParameterException e) { - throw new IOException(e + " " + e.getMessage()); - } - } - - public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, HttpConnectionParams params) throws IOException { - try { - return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); - } catch (NoSuchAlgorithmException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyManagementException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyStoreException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (InvalidAlgorithmParameterException e) { - throw new IOException(e + " " + e.getMessage()); - } - } - - - public Socket createSocket(String host, int port) throws IOException { - try { - return getSSLContext().getSocketFactory().createSocket(host, port); - } catch (NoSuchAlgorithmException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyManagementException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyStoreException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (InvalidAlgorithmParameterException e) { - throw new IOException(e + " " + e.getMessage()); - } - } - - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { - try { - return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); - } catch (NoSuchAlgorithmException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyManagementException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (KeyStoreException e) { - throw new IOException(e + " " + e.getMessage()); - } catch (InvalidAlgorithmParameterException e) { - throw new IOException(e + " " + e.getMessage()); - } - } - - /** - * All instances of SSLProtocolSocketFactory are the same. - */ - @Override - public boolean equals(Object obj) { - return ((obj != null) && obj.getClass().equals(this.getClass())); - } - - /** - * All instances of SSLProtocolSocketFactory have the same hash code. - */ - @Override - public int hashCode() { - return this.getClass().hashCode(); - } -} +/* + * 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.Settings; +import davmail.ui.PasswordPromptDialog; +import davmail.ui.tray.DavGatewayTray; +import org.apache.commons.httpclient.HttpsURL; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.Protocol; +import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; + +import javax.net.ssl.*; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.URL; +import java.security.*; +import java.util.ArrayList; + +/** + * Manual Socket Factory. + * Let user choose to accept or reject certificate + */ +public class DavGatewaySSLProtocolSocketFactory implements SecureProtocolSocketFactory { + /** + * Register custom Socket Factory to let user accept or reject certificate + */ + public static void register() { + String urlString = Settings.getProperty("davmail.url"); + try { + URL url = new URL(urlString); + String protocol = url.getProtocol(); + if ("https".equals(protocol)) { + int port = url.getPort(); + if (port < 0) { + port = HttpsURL.DEFAULT_PORT; + } + Protocol.registerProtocol(url.getProtocol(), + new Protocol(protocol, (ProtocolSocketFactory) new DavGatewaySSLProtocolSocketFactory(), port)); + } + } catch (MalformedURLException e) { + DavGatewayTray.error(new BundleMessage("LOG_INVALID_URL", urlString)); + } + } + + private KeyStore.ProtectionParameter getProtectionParameter(String password) { + if (password != null && password.length() > 0) { + // password provided: create a PasswordProtection + return new KeyStore.PasswordProtection(password.toCharArray()); + } else { + // request password at runtime through a callback + return new KeyStore.CallbackHandlerProtection(new CallbackHandler() { + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + if (callbacks.length > 0 && callbacks[0] instanceof PasswordCallback) { + PasswordPromptDialog passwordPromptDialog = new PasswordPromptDialog(((PasswordCallback) callbacks[0]).getPrompt()); + ((PasswordCallback) callbacks[0]).setPassword(passwordPromptDialog.getPassword()); + } + } + }); + } + } + + private SSLContext sslcontext; + + private SSLContext createSSLContext() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyManagementException, KeyStoreException { + // PKCS11 client certificate settings + String pkcs11Library = Settings.getProperty("davmail.ssl.pkcs11Library"); + + String clientKeystoreType = Settings.getProperty("davmail.ssl.clientKeystoreType"); + // set default keystore type + if (clientKeystoreType == null || clientKeystoreType.length() == 0) { + clientKeystoreType = "PKCS11"; + } + + if (pkcs11Library != null && pkcs11Library.length() > 0 && "PKCS11".equals(clientKeystoreType)) { + StringBuilder pkcs11Buffer = new StringBuilder(); + pkcs11Buffer.append("name=DavMail\n"); + pkcs11Buffer.append("library=").append(pkcs11Library).append('\n'); + String pkcs11Config = Settings.getProperty("davmail.ssl.pkcs11Config"); + if (pkcs11Config != null && pkcs11Config.length() > 0) { + pkcs11Buffer.append(pkcs11Config).append('\n'); + } + SunPKCS11ProviderHandler.registerProvider(pkcs11Buffer.toString()); + } + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(/*KeyManagerFactory.getDefaultAlgorithm()*/"NewSunX509"); + + ArrayList keyStoreBuilders = new ArrayList(); + // PKCS11 (smartcard) keystore with password callback + KeyStore.Builder scBuilder = KeyStore.Builder.newInstance("PKCS11", null, getProtectionParameter(null)); + keyStoreBuilders.add(scBuilder); + + String clientKeystoreFile = Settings.getProperty("davmail.ssl.clientKeystoreFile"); + String clientKeystorePass = Settings.getProperty("davmail.ssl.clientKeystorePass"); + if (clientKeystoreFile != null && clientKeystoreFile.length() > 0 + && ("PKCS12".equals(clientKeystoreType) || "JKS".equals(clientKeystoreType))) { + // PKCS12 file based keystore + KeyStore.Builder fsBuilder = KeyStore.Builder.newInstance(clientKeystoreType, null, + new File(clientKeystoreFile), getProtectionParameter(clientKeystorePass)); + keyStoreBuilders.add(fsBuilder); + } + + ManagerFactoryParameters keyStoreBuilderParameters = new KeyStoreBuilderParameters(keyStoreBuilders); + keyManagerFactory.init(keyStoreBuilderParameters); + + // Get a list of key managers + KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); + + // Walk through the key managers and replace all X509 Key Managers with + // a specialized wrapped DavMail X509 Key Manager + for (int i = 0; i < keyManagers.length; i++) { + KeyManager keyManager = keyManagers[i]; + if (keyManager instanceof X509KeyManager) { + keyManagers[i] = new DavMailX509KeyManager((X509KeyManager) keyManager); + } + } + + SSLContext context = SSLContext.getInstance("SSL"); + context.init(keyManagers, new TrustManager[]{new DavGatewayX509TrustManager()}, null); + return context; + } + + private SSLContext getSSLContext() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, InvalidAlgorithmParameterException { + if (this.sslcontext == null) { + this.sslcontext = createSSLContext(); + } + return this.sslcontext; + } + + public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException { + try { + return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); + } catch (NoSuchAlgorithmException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyManagementException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyStoreException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (InvalidAlgorithmParameterException e) { + throw new IOException(e + " " + e.getMessage()); + } + } + + public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, HttpConnectionParams params) throws IOException { + try { + return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); + } catch (NoSuchAlgorithmException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyManagementException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyStoreException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (InvalidAlgorithmParameterException e) { + throw new IOException(e + " " + e.getMessage()); + } + } + + public Socket createSocket(String host, int port) throws IOException { + try { + return getSSLContext().getSocketFactory().createSocket(host, port); + } catch (NoSuchAlgorithmException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyManagementException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyStoreException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (InvalidAlgorithmParameterException e) { + throw new IOException(e + " " + e.getMessage()); + } + } + + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + try { + return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); + } catch (NoSuchAlgorithmException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyManagementException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (KeyStoreException e) { + throw new IOException(e + " " + e.getMessage()); + } catch (InvalidAlgorithmParameterException e) { + throw new IOException(e + " " + e.getMessage()); + } + } + + /** + * All instances of SSLProtocolSocketFactory are the same. + */ + @Override + public boolean equals(Object obj) { + return ((obj != null) && obj.getClass().equals(this.getClass())); + } + + /** + * All instances of SSLProtocolSocketFactory have the same hash code. + */ + @Override + public int hashCode() { + return this.getClass().hashCode(); + } +} diff --git a/src/java/davmail/http/DavMailX509KeyManager.java b/src/java/davmail/http/DavMailX509KeyManager.java new file mode 100644 index 00000000..42397866 --- /dev/null +++ b/src/java/davmail/http/DavMailX509KeyManager.java @@ -0,0 +1,165 @@ +/* + * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway + * Copyright (C) 2011 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.ui.SelectCertificateDialog; +import org.apache.log4j.Logger; + +import javax.net.ssl.X509KeyManager; +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Special X509 Key Manager that handles cases where more than one private key + * is sufficient to establish the HTTPs connection by asking the user to + * select one. + */ +public class DavMailX509KeyManager implements X509KeyManager { + + protected static final Logger LOGGER = Logger.getLogger(DavMailX509KeyManager.class); + + // Wrap an existing key manager to handle most of the interface as a pass through + private final X509KeyManager keyManager; + + // Remember selected alias so we don't continually bug the user + private String cachedAlias; + + /** + * Build the specialized key manager wrapping the default one + * + * @param keyManager original key manager + */ + public DavMailX509KeyManager(X509KeyManager keyManager) { + this.keyManager = keyManager; + } + + /** + * Get the client aliases, simply pass this through to wrapped key manager + */ + public String[] getClientAliases(String string, Principal[] principals) { + return keyManager.getClientAliases(string, principals); + } + + /** + * Select a client alias. Some servers are misconfigured and claim to accept + * any client certificate during the SSL handshake, however OWA only authenticates + * using a single certificate. + *

+ * This method allows the user to select the right client certificate + */ + public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { + // Build a list of all aliases + ArrayList aliases = new ArrayList(); + for (String keyTypeValue : keyType) { + String[] keyAliases = keyManager.getClientAliases(keyTypeValue, issuers); + + if (keyAliases != null) { + aliases.addAll(Arrays.asList(keyAliases)); + } + } + + // If there are more than one show a dialog and return the selected alias + if (aliases.size() > 1) { + + //If there's a saved pattern try to match it + if (cachedAlias != null) { + for (String alias : aliases) { + if (cachedAlias.equals(stripAlias(alias))) { + LOGGER.debug(alias + " matched cached alias: " + cachedAlias); + return alias; + } + } + + // pattern didn't match, clear the pattern and ask user to select an alias + cachedAlias = null; + } + + String[] aliasesArray = aliases.toArray(new String[aliases.size()]); + SelectCertificateDialog selectCertificateDialog = new SelectCertificateDialog(aliasesArray); + + LOGGER.debug("User selected Key Alias: " + selectCertificateDialog.getSelectedAlias()); + + cachedAlias = stripAlias(selectCertificateDialog.getSelectedAlias().substring(10)); + LOGGER.debug("Stored Key Alias Pattern: " + cachedAlias); + + return selectCertificateDialog.getSelectedAlias(); + + // exactly one, simply return that and don't bother the user + } else if (aliases.size() == 1) { + LOGGER.debug("One Private Key found, returning that"); + return aliases.get(0); + + // none, return null + } else { + LOGGER.debug("No Private Keys found"); + return null; + } + } + + /** + * PKCS11 aliases are in the format: dd.0, dd is incremented + * every time the SSL connection is re-negotiated + * + * @param alias original alias + * @return alias without prefix + */ + protected String stripAlias(String alias) { + String value = alias; + if (value != null && value.length() > 1) { + char firstChar = value.charAt(0); + int dotIndex = value.indexOf('.'); + if (firstChar >= '0' && firstChar <= '9' && dotIndex >= 0) { + value = value.substring(dotIndex+1); + } + } + return value; + } + + /** + * Passthrough to wrapped keymanager + */ + public String[] getServerAliases(String string, Principal[] prncpls) { + return keyManager.getServerAliases(string, prncpls); + } + + /** + * Passthrough to wrapped keymanager + */ + public String chooseServerAlias(String string, Principal[] prncpls, Socket socket) { + return keyManager.chooseServerAlias(string, prncpls, socket); + } + + /** + * Passthrough to wrapped keymanager + */ + public X509Certificate[] getCertificateChain(String string) { + return keyManager.getCertificateChain(string); + } + + /** + * Passthrough to wrapped keymanager + */ + public PrivateKey getPrivateKey(String string) { + return keyManager.getPrivateKey(string); + } +} diff --git a/src/java/davmail/ui/SelectCertificateDialog.java b/src/java/davmail/ui/SelectCertificateDialog.java new file mode 100644 index 00000000..38301314 --- /dev/null +++ b/src/java/davmail/ui/SelectCertificateDialog.java @@ -0,0 +1,111 @@ +/* + * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway + * Copyright (C) 2011 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.ui; + +import davmail.BundleMessage; +import davmail.ui.tray.DavGatewayTray; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * Let user select a client certificate + */ +public class SelectCertificateDialog extends JDialog { + protected JList aliasListBox; + protected String selectedAlias; + + /** + * Gets user selected alias. + * + * @return user selected alias + */ + public String getSelectedAlias() { + return this.selectedAlias; + } + + /** + * Select a client certificate + * + * @param aliases An array of certificate aliases for the user to pick from + */ + public SelectCertificateDialog(String[] aliases) { + setAlwaysOnTop(true); + + setTitle(BundleMessage.format("UI_CERTIFICATE_ALIAS_PROMPT")); + try { + setIconImage(DavGatewayTray.getFrameIcon()); + } catch (NoSuchMethodError error) { + DavGatewayTray.debug(new BundleMessage("LOG_UNABLE_TO_SET_ICON_IMAGE")); + } + + JPanel questionPanel = new JPanel(); + questionPanel.setLayout(new BoxLayout(questionPanel, BoxLayout.Y_AXIS)); + JLabel imageLabel = new JLabel(); + imageLabel.setIcon(UIManager.getIcon("OptionPane.questionIcon")); + imageLabel.setText(BundleMessage.format("UI_CERTIFICATE_ALIAS_PROMPT")); + questionPanel.add(imageLabel); + + aliasListBox = new JList(aliases); + aliasListBox.setMaximumSize(aliasListBox.getPreferredSize()); + + JPanel aliasPanel = new JPanel(); + aliasPanel.setLayout(new BoxLayout(aliasPanel, BoxLayout.Y_AXIS)); + aliasPanel.add(aliasListBox); + + add(questionPanel, BorderLayout.NORTH); + add(aliasPanel, BorderLayout.CENTER); + add(getButtonPanel(), BorderLayout.SOUTH); + setModal(true); + + pack(); + // center frame + setLocation(getToolkit().getScreenSize().width / 2 - + getSize().width / 2, + getToolkit().getScreenSize().height / 2 - + getSize().height / 2); + setVisible(true); + requestFocus(); + } + + protected JPanel getButtonPanel() { + JPanel buttonPanel = new JPanel(); + JButton okButton = new JButton(BundleMessage.format("UI_BUTTON_OK")); + JButton cancelButton = new JButton(BundleMessage.format("UI_BUTTON_CANCEL")); + okButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + selectedAlias = aliasListBox.getSelectedValue().toString(); + setVisible(false); + } + }); + cancelButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + selectedAlias = null; + setVisible(false); + } + }); + + buttonPanel.add(okButton); + buttonPanel.add(cancelButton); + return buttonPanel; + } + +}