| /******************************************************************************* |
| * Copyright (C) 2007 The University of Manchester |
| * |
| * Modifications to the initial code base are copyright of their |
| * respective authors, or their employers as appropriate. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public License |
| * as published by the Free Software Foundation; either version 2.1 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 |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| ******************************************************************************/ |
| package net.sf.taverna.t2.workbench.ui.credentialmanager; |
| |
| import static java.awt.BorderLayout.CENTER; |
| import static java.awt.BorderLayout.NORTH; |
| import static java.awt.BorderLayout.PAGE_END; |
| import static java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE; |
| import static java.awt.Toolkit.getDefaultToolkit; |
| import static javax.swing.JFileChooser.APPROVE_OPTION; |
| import static javax.swing.JOptionPane.ERROR_MESSAGE; |
| import static javax.swing.JOptionPane.INFORMATION_MESSAGE; |
| import static javax.swing.JOptionPane.NO_OPTION; |
| import static javax.swing.JOptionPane.WARNING_MESSAGE; |
| import static javax.swing.JOptionPane.YES_NO_OPTION; |
| import static javax.swing.JOptionPane.YES_OPTION; |
| import static javax.swing.JOptionPane.showConfirmDialog; |
| import static javax.swing.JOptionPane.showMessageDialog; |
| import static javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS; |
| import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED; |
| import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED; |
| import static org.apache.taverna.security.credentialmanager.CredentialManager.KeystoreType.KEYSTORE; |
| import static org.apache.taverna.security.credentialmanager.CredentialManager.KeystoreType.TRUSTSTORE; |
| import static net.sf.taverna.t2.workbench.ui.credentialmanager.CMStrings.ALERT_TITLE; |
| import static net.sf.taverna.t2.workbench.ui.credentialmanager.CMStrings.ERROR_TITLE; |
| |
| import java.awt.BorderLayout; |
| import java.awt.Dimension; |
| import java.awt.FlowLayout; |
| import java.awt.Image; |
| import java.awt.Point; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.awt.event.WindowAdapter; |
| import java.awt.event.WindowEvent; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileWriter; |
| import java.io.InputStreamReader; |
| import java.net.URI; |
| import java.security.Key; |
| import java.security.KeyStore; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateFactory; |
| import java.security.cert.X509Certificate; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.prefs.Preferences; |
| |
| import javax.swing.JButton; |
| import javax.swing.JFileChooser; |
| import javax.swing.JFrame; |
| import javax.swing.JPanel; |
| import javax.swing.JScrollPane; |
| import javax.swing.JTabbedPane; |
| import javax.swing.JTable; |
| import javax.swing.border.EmptyBorder; |
| import javax.swing.event.ListSelectionEvent; |
| import javax.swing.event.ListSelectionListener; |
| import javax.swing.table.TableColumn; |
| |
| import org.apache.taverna.security.credentialmanager.CMException; |
| import org.apache.taverna.security.credentialmanager.CredentialManager; |
| import org.apache.taverna.security.credentialmanager.CredentialManager.KeystoreType; |
| import org.apache.taverna.security.credentialmanager.DistinguishedNameParser; |
| import org.apache.taverna.security.credentialmanager.UsernamePassword; |
| |
| import org.apache.log4j.Logger; |
| import org.bouncycastle.openssl.PEMReader; |
| import org.bouncycastle.openssl.PEMWriter; |
| |
| /** |
| * Provides a UI for the Credential Manager for users to manage their |
| * credentials saved by the Credential Manager in Taverna's Keystore and |
| * Trustore. Credentials include username and passwords pairs, key pairs, proxy |
| * key pairs and trusted certificates of CA's and s. Credentials are stored in |
| * two Bouncy Castle "UBER"-type keystores: the Keystore (containing passwords |
| * and (normal and proxy) key pairs) and the Truststore (containing trusted |
| * certificates). |
| * |
| * Inspired by the Portlecle tool (http://portecle.sourceforge.net/) |
| * and Firefox's Certificate Manager. |
| * |
| * @author Alex Nenadic |
| */ |
| |
| @SuppressWarnings("serial") |
| public class CredentialManagerUI extends JFrame { |
| private static Logger logger = Logger.getLogger(CredentialManagerUI.class); |
| /** Default tabbed pane width */ |
| private static final int DEFAULT_FRAME_WIDTH = 650; |
| /** Default tabbed pane height */ |
| private static final int DEFAULT_FRAME_HEIGHT = 400; |
| /** Credential Manager icon (when frame is minimised)*/ |
| private static final Image credManagerIconImage = getDefaultToolkit() |
| .createImage( |
| CredentialManagerUI.class |
| .getResource("/images/cred_manager_transparent.png")); |
| |
| /** |
| * Credential Manager to manage all operations on the Keystore and |
| * Truststore |
| */ |
| public final CredentialManager credManager; |
| private final DistinguishedNameParser dnParser; |
| |
| ////////////// Tabs ////////////// |
| |
| /** |
| * Tabbed pane to hold tables containing various entries in the Keystore and |
| * Truststore |
| */ |
| private JTabbedPane keyStoreTabbedPane; |
| /** Tab 1: holds passwords table */ |
| private JPanel passwordsTab = new JPanel(new BorderLayout(10, 10)); |
| /** Tab 1: name */ |
| public static final String PASSWORDS = "Passwords"; |
| /** Tab 2: holds key pairs (user certificates) table */ |
| private JPanel keyPairsTab = new JPanel(new BorderLayout(10, 10)); |
| /** Tab 2: name */ |
| public static final String KEYPAIRS = "Your Certificates"; |
| /** Tab 3: holds trusted certificates table */ |
| private JPanel trustedCertificatesTab = new JPanel(new BorderLayout(10, 10)); |
| /** Tab 3: name */ |
| public static final String TRUSTED_CERTIFICATES = "Trusted Certificates"; |
| |
| ////////////// Tables ////////////// |
| |
| /** Password entries' table */ |
| private JTable passwordsTable; |
| /** Key pair entries' table */ |
| private JTable keyPairsTable; |
| /** Trusted certificate entries' table */ |
| private JTable trustedCertsTable; |
| /** Password entry column type */ |
| public static final String PASSWORD_ENTRY_TYPE = "Password"; |
| /** Key pair entry column type */ |
| public static final String KEY_PAIR_ENTRY_TYPE = "Key Pair"; |
| /** Trusted cert entry column type */ |
| public static final String TRUST_CERT_ENTRY_TYPE = "Trusted Certificate"; |
| |
| /** |
| * Overrides the Object's clone method to prevent the singleton object to be |
| * cloned. |
| */ |
| @Override |
| public Object clone() throws CloneNotSupportedException { |
| throw new CloneNotSupportedException(); |
| } |
| |
| /** |
| * Creates a new Credential Manager UI's frame. |
| */ |
| public CredentialManagerUI(CredentialManager credentialManager, |
| DistinguishedNameParser dnParser) { |
| credManager = credentialManager; |
| this.dnParser = dnParser; |
| setModalExclusionType(APPLICATION_EXCLUDE); |
| // Initialise the UI components |
| initComponents(); |
| } |
| |
| private void initComponents() { |
| /* |
| * Initialise the tabbed pane that contains the tabs with tabular |
| * representations of the Keystore's content. |
| */ |
| keyStoreTabbedPane = new JTabbedPane(); |
| /* |
| * Initialise the tab containing the table for username/password entries |
| * from the Keystore |
| */ |
| passwordsTable = initTable(PASSWORDS, passwordsTab); |
| /* |
| * Initialise the tab containing the table for key pair entries from the |
| * Keystore |
| */ |
| keyPairsTable = initTable(KEYPAIRS, keyPairsTab); |
| /* |
| * Initialise the tab containing the table for proxy entries from the |
| * Keystore |
| */ |
| //proxiesTable = initTable(PROXIES, proxiesTab); |
| /* |
| * Initialise the tab containing the table for trusted certificate |
| * entries from the Truststore |
| */ |
| trustedCertsTable = initTable(TRUSTED_CERTIFICATES, |
| trustedCertificatesTab); |
| /* |
| * Set the size of the tabbed pane to the preferred size - the size of |
| * the main application frame depends on it. |
| */ |
| keyStoreTabbedPane.setPreferredSize(new Dimension(DEFAULT_FRAME_WIDTH, |
| DEFAULT_FRAME_HEIGHT)); |
| |
| JPanel globalButtons = new JPanel(new FlowLayout(FlowLayout.RIGHT)); |
| JButton resetJavaAuthCache = new JButton("Clear HTTP authentication"); |
| resetJavaAuthCache.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| clearAuthenticationCache(); |
| } |
| }); |
| globalButtons.add(resetJavaAuthCache); |
| |
| // Button for changing Credential Manager's master password |
| JButton changeMasterPasswordButton = new JButton( |
| "Change master password"); |
| changeMasterPasswordButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| changeMasterPassword(); |
| } |
| }); |
| globalButtons.add(changeMasterPasswordButton); |
| |
| // Add change master password to the main application frame |
| getContentPane().add(globalButtons, NORTH); |
| // Add tabbed pane to the main application frame |
| getContentPane().add(keyStoreTabbedPane, CENTER); |
| |
| // Handle application close |
| addWindowListener(new WindowAdapter() { |
| @Override |
| public void windowClosing(WindowEvent evt) { |
| closeFrame(); |
| } |
| }); |
| setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); |
| |
| pack(); |
| |
| // Centre the frame in the centre of the screen |
| setLocationRelativeTo(null); |
| |
| // Set the frame's icon |
| setIconImage(credManagerIconImage); |
| |
| // Set the frame's title |
| setTitle("Credential Manager"); |
| |
| // setModal(true); |
| // setVisible(true); |
| } |
| |
| protected void clearAuthenticationCache() { |
| if (!credManager.resetAuthCache()) |
| showMessageDialog( |
| this, |
| "Java's internal HTTP authentication cache could not be cleared. \n\n" |
| + "Taverna can only clear the cache using an undocumented Java API \n" |
| + "that might not work if you are using a Java VM other than \n" |
| + "Java 6 from Sun. You can restarting Taverna to clear the cache.", |
| "Could not clear authentication cache", ERROR_MESSAGE); |
| else |
| showMessageDialog( |
| this, |
| "Java's internal HTTP authentication cache has been cleared. \n\n" |
| + "You might also need to edit or delete individual \n" |
| + "password entries in the credential manager \n" |
| + "if a relevant password has previously been saved.", |
| "Cleared authentication cache", INFORMATION_MESSAGE); |
| } |
| |
| protected void changeMasterPassword() { |
| ChangeMasterPasswordDialog changePasswordDialog = new ChangeMasterPasswordDialog( |
| this, "Change master password", true, |
| "Change master password for Credential Manager", credManager); |
| changePasswordDialog.setLocationRelativeTo(null); |
| changePasswordDialog.setVisible(true); |
| String password = changePasswordDialog.getPassword(); |
| if (password == null) // user cancelled |
| return; // do nothing |
| |
| try { |
| credManager.changeMasterPassword(password); |
| showMessageDialog(this, "Master password changed sucessfully", |
| ALERT_TITLE, INFORMATION_MESSAGE); |
| } catch (CMException cme) { |
| /* |
| * Failed to change the master password for Credential Manager - |
| * warn the user |
| */ |
| String exMessage = "Failed to change master password for Credential Manager"; |
| logger.error(exMessage); |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| } |
| |
| /** |
| * Initialise the tabs and tables with the content from the Keystore and Truststore. |
| */ |
| private JTable initTable(String tableType, JPanel tab) { |
| JTable table = null; |
| |
| if (tableType.equals(PASSWORDS)) { // Passwords table |
| // The Passwords table's data model |
| PasswordsTableModel passwordsTableModel = new PasswordsTableModel(credManager); |
| // The table itself |
| table = new JTable(passwordsTableModel); |
| |
| /* |
| * Set the password and alias columns of the Passwords table to be |
| * invisible by removing them from the column model (they will still |
| * present in the table model) |
| * |
| * Remove the last column first |
| */ |
| TableColumn aliasColumn = table.getColumnModel().getColumn(5); |
| table.getColumnModel().removeColumn(aliasColumn); |
| TableColumn passwordColumn = table.getColumnModel().getColumn(4); |
| table.getColumnModel().removeColumn(passwordColumn); |
| TableColumn lastModifiedDateColumn = table.getColumnModel().getColumn(3); |
| table.getColumnModel().removeColumn(lastModifiedDateColumn); |
| |
| // Buttons |
| JButton newPasswordButton = new JButton("New"); |
| newPasswordButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| newPassword(); |
| } |
| }); |
| |
| final JButton viewPasswordButton = new JButton("Details"); |
| viewPasswordButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| viewPassword(); |
| } |
| }); |
| viewPasswordButton.setEnabled(false); |
| |
| final JButton editPasswordButton = new JButton("Edit"); |
| editPasswordButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| editPassword(); |
| } |
| }); |
| editPasswordButton.setEnabled(false); |
| |
| final JButton deletePasswordButton = new JButton("Delete"); |
| deletePasswordButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| deletePassword(); |
| } |
| }); |
| deletePasswordButton.setEnabled(false); |
| |
| /* |
| * Selection listener for passwords table to enable/disable action |
| * buttons accordingly |
| */ |
| class PasswordsTableSelectionListner implements |
| ListSelectionListener { |
| @Override |
| public void valueChanged(ListSelectionEvent e) { |
| if (e.getSource() != passwordsTable.getSelectionModel()) |
| return; |
| if (passwordsTable.getSelectedRow() == -1) { |
| // nothing is selected |
| viewPasswordButton.setEnabled(false); |
| editPasswordButton.setEnabled(false); |
| deletePasswordButton.setEnabled(false); |
| } else { |
| if (!viewPasswordButton.isEnabled()) |
| viewPasswordButton.setEnabled(true); |
| if (!editPasswordButton.isEnabled()) |
| editPasswordButton.setEnabled(true); |
| if (!deletePasswordButton.isEnabled()) |
| deletePasswordButton.setEnabled(true); |
| } |
| } |
| } |
| table.getSelectionModel().addListSelectionListener(new PasswordsTableSelectionListner()); |
| |
| // Panel to hold the buttons |
| JPanel bp = new JPanel(); |
| bp.add(viewPasswordButton); |
| bp.add(editPasswordButton); |
| bp.add(newPasswordButton); |
| bp.add(deletePasswordButton); |
| |
| // Add button panel to the tab |
| tab.add(bp, PAGE_END); |
| |
| } else if (tableType.equals(KEYPAIRS)) { // Key Pairs tab |
| // The Key Pairs table's data model |
| KeyPairsTableModel keyPairsTableModel = new KeyPairsTableModel(credManager); |
| // The table itself |
| table = new JTable(keyPairsTableModel); |
| |
| /* |
| * Set the alias and service URIs columns of the KayPairs table to |
| * be invisible by removing them from the column model (they will |
| * still present in the table model) |
| * |
| * Remove the last column first |
| */ |
| TableColumn aliasColumn = table.getColumnModel().getColumn(6); |
| table.getColumnModel().removeColumn(aliasColumn); |
| TableColumn serviceURIsColumn = table.getColumnModel().getColumn(5); |
| table.getColumnModel().removeColumn(serviceURIsColumn); |
| TableColumn lastModifiedDateColumn = table.getColumnModel().getColumn(4); |
| table.getColumnModel().removeColumn(lastModifiedDateColumn); |
| |
| // Buttons |
| final JButton viewKeyPairButton = new JButton("Details"); |
| viewKeyPairButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| viewCertificate(); |
| } |
| }); |
| viewKeyPairButton.setEnabled(false); |
| |
| JButton importKeyPairButton = new JButton("Import"); |
| importKeyPairButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| importKeyPair(); |
| } |
| }); |
| |
| final JButton exportKeyPairButton = new JButton("Export"); |
| exportKeyPairButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| exportKeyPair(); |
| } |
| }); |
| exportKeyPairButton.setEnabled(false); |
| |
| final JButton deleteKeyPairButton = new JButton("Delete"); |
| deleteKeyPairButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| deleteKeyPair(); |
| } |
| }); |
| deleteKeyPairButton.setEnabled(false); |
| |
| /* |
| * Selection listener for key pairs table to enable/disable action |
| * buttons accordingly |
| */ |
| class KeyPairsTableSelectionListner implements |
| ListSelectionListener { |
| @Override |
| public void valueChanged(ListSelectionEvent e) { |
| if (e.getSource() != keyPairsTable.getSelectionModel()) |
| return; |
| if (keyPairsTable.getSelectedRow() == -1) { |
| // nothing is selected |
| viewKeyPairButton.setEnabled(false); |
| exportKeyPairButton.setEnabled(false); |
| deleteKeyPairButton.setEnabled(false); |
| } else { |
| if (!viewKeyPairButton.isEnabled()) |
| viewKeyPairButton.setEnabled(true); |
| if (!exportKeyPairButton.isEnabled()) |
| exportKeyPairButton.setEnabled(true); |
| if (!deleteKeyPairButton.isEnabled()) |
| deleteKeyPairButton.setEnabled(true); |
| } |
| } |
| } |
| table.getSelectionModel().addListSelectionListener( |
| new KeyPairsTableSelectionListner()); |
| |
| // Panel to hold the buttons |
| JPanel bp = new JPanel(); |
| bp.add(viewKeyPairButton); |
| bp.add(importKeyPairButton); |
| bp.add(exportKeyPairButton); |
| bp.add(deleteKeyPairButton); |
| |
| // Add button panel to the tab |
| tab.add(bp, PAGE_END); |
| } else if (tableType.equals(TRUSTED_CERTIFICATES)) { // Certificates tab |
| |
| // The Trusted Certificate table's data model |
| TrustedCertsTableModel trustedCertificatesTableModel = new TrustedCertsTableModel(credManager); |
| // The table itself |
| table = new JTable(trustedCertificatesTableModel); |
| |
| /* |
| * Set the alias columns of the Trusted Certs table to be invisible |
| * by removing them from the column model (they will still be |
| * present in the table model) |
| * |
| * Remove the last column first |
| */ |
| TableColumn aliasColumn = table.getColumnModel().getColumn(5); |
| table.getColumnModel().removeColumn(aliasColumn); |
| TableColumn lastModifiedDateColumn = table.getColumnModel().getColumn(4); |
| table.getColumnModel().removeColumn(lastModifiedDateColumn); |
| |
| // Buttons |
| final JButton viewTrustedCertificateButton = new JButton("Details"); |
| viewTrustedCertificateButton |
| .addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| viewCertificate(); |
| } |
| }); |
| viewTrustedCertificateButton.setEnabled(false); |
| |
| JButton importTrustedCertificateButton = new JButton("Import"); |
| importTrustedCertificateButton |
| .addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| importTrustedCertificate(); |
| } |
| }); |
| |
| final JButton exportTrustedCertificateButton = new JButton("Export"); |
| exportTrustedCertificateButton |
| .addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| exportTrustedCertificate(); |
| } |
| }); |
| exportTrustedCertificateButton.setEnabled(false); |
| |
| final JButton deleteTrustedCertificateButton = new JButton("Delete"); |
| deleteTrustedCertificateButton |
| .addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| deleteTrustedCertificate(); |
| } |
| }); |
| deleteTrustedCertificateButton.setEnabled(false); |
| |
| // Selection listener for trusted certs table to enable/disable action buttons accordingly |
| class TrustedCertsTableSelectionListener implements |
| ListSelectionListener { |
| @Override |
| public void valueChanged(ListSelectionEvent e) { |
| if (e.getSource() != trustedCertsTable.getSelectionModel()) |
| return; |
| if (trustedCertsTable.getSelectedRow() == -1) { |
| // nothing is selected |
| viewTrustedCertificateButton.setEnabled(false); |
| exportTrustedCertificateButton.setEnabled(false); |
| deleteTrustedCertificateButton.setEnabled(false); |
| } else { |
| if (!viewTrustedCertificateButton.isEnabled()) |
| viewTrustedCertificateButton.setEnabled(true); |
| if (!exportTrustedCertificateButton.isEnabled()) |
| exportTrustedCertificateButton.setEnabled(true); |
| if (!deleteTrustedCertificateButton.isEnabled()) |
| deleteTrustedCertificateButton.setEnabled(true); |
| } |
| } |
| } |
| table.getSelectionModel().addListSelectionListener( |
| new TrustedCertsTableSelectionListener()); |
| |
| // Panel to hold the buttons |
| JPanel bp = new JPanel(); |
| bp.add(viewTrustedCertificateButton); |
| bp.add(importTrustedCertificateButton); |
| bp.add(exportTrustedCertificateButton); |
| bp.add(deleteTrustedCertificateButton); |
| |
| // Add button panel to the tab |
| tab.add(bp, PAGE_END); |
| } else { |
| throw new RuntimeException("Unknown table type " + tableType); |
| } |
| |
| table.setShowGrid(false); |
| table.setRowMargin(0); |
| table.getColumnModel().setColumnMargin(0); |
| table.getTableHeader().setReorderingAllowed(false); |
| table.setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS); |
| // Top accommodates entry icons with 2 pixels spare space (images are |
| // 16x16 pixels) |
| table.setRowHeight(18); |
| |
| // Add custom renderrers for the table headers and cells |
| for (int iCnt = 0; iCnt < table.getColumnCount(); iCnt++) { |
| TableColumn column = table.getColumnModel().getColumn(iCnt); |
| column.setHeaderRenderer(new TableHeaderRenderer()); |
| column.setCellRenderer(new TableCellRenderer()); |
| } |
| |
| // Make the first column small and not resizable (it holds icons to |
| // represent different entry types) |
| TableColumn typeCol = table.getColumnModel().getColumn(0); |
| typeCol.setResizable(false); |
| typeCol.setMinWidth(20); |
| typeCol.setMaxWidth(20); |
| typeCol.setPreferredWidth(20); |
| |
| // Set the size for the second column |
| // (i.e. Service URI column of Passwords table, and |
| // Certificate Name column of the Kay Pairs and Trusted Certificates tables) |
| // We do not care about the size of other columns. |
| TableColumn secondCol = table.getColumnModel().getColumn(1); |
| secondCol.setMinWidth(20); |
| secondCol.setMaxWidth(10000); |
| secondCol.setPreferredWidth(300); |
| |
| // Put the table into a scroll pane |
| JScrollPane jspTableScrollPane = new JScrollPane(table, |
| VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); |
| jspTableScrollPane.getViewport().setBackground(table.getBackground()); |
| |
| // Put the scroll pane on the tab panel |
| tab.add(jspTableScrollPane, CENTER); |
| jspTableScrollPane.setBorder(new EmptyBorder(3, 3, 3, 3)); |
| |
| /* |
| * Add mouse listeners to show an entry's details if it is |
| * double-clicked |
| */ |
| table.addMouseListener(new MouseAdapter() { |
| @Override |
| public void mouseClicked(MouseEvent evt) { |
| tableDoubleClick(evt); |
| } |
| }); |
| |
| // Add the tab to the tabbed pane |
| keyStoreTabbedPane.addTab(tableType, tab); |
| |
| return table; |
| } |
| |
| /** |
| * Displays the details of the username/password pair entry - this includes |
| * showing the plaintext password and service URI for this entry. |
| */ |
| private void viewPassword() { |
| // Which username/password pair entry has been selected, if any? |
| int iRow = passwordsTable.getSelectedRow(); |
| if (iRow == -1) // no row currently selected |
| return; |
| |
| // Get current values for service URI, username and password |
| String serviceURI = (String) passwordsTable.getValueAt(iRow, 1); // current entry's service URI |
| |
| String username = (String) passwordsTable.getValueAt(iRow, 2); // current entry's username |
| |
| /* |
| * Because the password column is not visible we call the getValueAt |
| * method on the table model rather than at the JTable |
| */ |
| String password = (String) passwordsTable.getModel() |
| .getValueAt(iRow, 4); // current entry's password value |
| |
| // Let the user view service URI, username and password of the entry |
| ViewUsernamePasswordEntryDialog viewServicePassDialog = new ViewUsernamePasswordEntryDialog( |
| this, serviceURI, username, password); |
| |
| viewServicePassDialog.setLocationRelativeTo(this); |
| viewServicePassDialog.setVisible(true); |
| } |
| |
| /** |
| * Lets a user insert a new username/password/service URI tuple to the |
| * Keystore. |
| */ |
| private void newPassword() { |
| URI serviceURI = null; // service URI |
| String username = null; // username |
| String password = null; // password |
| |
| // Loop until the user cancels or enters everything correctly |
| while (true) { |
| /* |
| * Let the user insert a new password entry (by specifying service |
| * URI, username and password) |
| */ |
| NewEditPasswordEntryDialog newPasswordDialog = new NewEditPasswordEntryDialog( |
| this, "New username and password for a service", true, |
| serviceURI, username, password, credManager); |
| newPasswordDialog.setLocationRelativeTo(this); |
| newPasswordDialog.setVisible(true); |
| |
| serviceURI = newPasswordDialog.getServiceURI(); // get service URI |
| username = newPasswordDialog.getUsername(); // get username |
| password = newPasswordDialog.getPassword(); // get password |
| |
| if (password == null) { // user cancelled - any of the above three |
| // fields is null |
| // do nothing |
| return; |
| } |
| |
| /* |
| * Check if a password entry with the given service URI already |
| * exists in the Keystore. We ask this here as the user may wish to |
| * overwrite the existing password entry. Checking for key pair |
| * entries' URIs is done in the NewEditPasswordEntry dialog. |
| */ |
| |
| /* |
| * Get list of service URIs for all the password entries in the |
| * Keystore |
| */ |
| List<URI> serviceURIs = null; |
| try { |
| serviceURIs = credManager |
| .getServiceURIsForAllUsernameAndPasswordPairs(); |
| } catch (CMException cme) { |
| showMessageDialog(this, "Failed to get service URIs for all username and password pairs " |
| + "to check if the entered service URI already exists", |
| ERROR_TITLE, ERROR_MESSAGE); |
| return; |
| } |
| if (serviceURIs.contains(serviceURI)) { // if such a URI already |
| // exists |
| // Ask if the user wants to overwrite it |
| int answer = showConfirmDialog( |
| this, |
| "Credential Manager already contains a password entry with the same service URI.\n" |
| + "Do you want to overwrite it?", |
| ALERT_TITLE, |
| YES_NO_OPTION); |
| |
| // Add the new password entry in the Keystore |
| try { |
| if (answer == YES_OPTION) { |
| credManager.addUsernameAndPasswordForService( |
| new UsernamePassword(username, password), |
| serviceURI); |
| break; |
| } |
| } catch (CMException cme) { |
| showMessageDialog( |
| this, |
| "Credential Manager failed to insert a new username and password pair", |
| ERROR_TITLE, ERROR_MESSAGE); |
| } |
| /* |
| * Otherwise show the same window with the entered service URI, |
| * username and password values |
| */ |
| } else |
| // Add the new password entry in the Keystore |
| try { |
| credManager.addUsernameAndPasswordForService(new UsernamePassword(username, |
| password), serviceURI); |
| break; |
| } catch (CMException cme) { |
| showMessageDialog( |
| this, |
| "Credential Manager failed to insert a new username and password pair", |
| ERROR_TITLE, ERROR_MESSAGE); |
| } |
| } |
| } |
| |
| /** |
| * Lets a user insert a new username/password pair for a given service URI |
| * to the Keystore. |
| */ |
| public void newPasswordForService(URI serviceURI) { |
| /* |
| * As this method can be called from outside of Credential Manager UI, |
| * e.g. from wsdl-activity-ui or rshell-activity-ui to pop up a dialog |
| * to ask the user for username and password, we also want to make sure |
| * the main Credential Manager UI Dialog is visible as it may be clearer |
| * to the user what is going on |
| */ |
| if (!isVisible() || getState() == ICONIFIED) |
| setVisible(true); |
| |
| // Make sure password tab is selected as this method may |
| // be called from outside of Credential Manager UI. |
| keyStoreTabbedPane.setSelectedComponent(passwordsTab); |
| |
| String username = null; // username |
| String password = null; // password |
| |
| // Loop until the user cancels or enters everything correctly |
| while (true) { |
| |
| // if(!this.isVisible()){ // if Cred Man UI is already showing but e.g. obscured by another window or minimised |
| // // Do not bring it up! |
| // } // actually we now want to show it as it makes it clearer to the user what is going on |
| |
| // Let the user insert a new password entry for the given service |
| // URI (by specifying username and password) |
| NewEditPasswordEntryDialog newPasswordDialog = new NewEditPasswordEntryDialog( |
| this, "New username and password for a service", true, |
| serviceURI, username, password, credManager); |
| newPasswordDialog.setLocationRelativeTo(this); |
| newPasswordDialog.setVisible(true); |
| |
| serviceURI = newPasswordDialog.getServiceURI(); // get service URI |
| username = newPasswordDialog.getUsername(); // get username |
| password = newPasswordDialog.getPassword(); // get password |
| |
| if (password == null) // user cancelled - any of the above three |
| // fields is null |
| // do nothing |
| return; |
| |
| /* |
| * Check if a password entry with the given service URI already |
| * exists in the Keystore. We ask this here as the user may wish to |
| * overwrite the existing password entry. Checking for key pair |
| * entries' URIs is done in the NewEditPasswordEntry dialog. |
| */ |
| |
| // Get list of service URIs for all the password entries in the |
| // Keystore |
| List<URI> serviceURIs = null; |
| try { |
| serviceURIs = credManager |
| .getServiceURIsForAllUsernameAndPasswordPairs(); |
| } catch (CMException cme) { |
| showMessageDialog(this, "Failed to get service URIs for all username and password pairs " |
| + "to check if the entered service URI already exists", |
| ERROR_TITLE, ERROR_MESSAGE); |
| return; |
| } |
| if (serviceURIs.contains(serviceURI)) { // if such a URI already |
| // exists |
| // Ask if the user wants to overwrite it |
| int answer = showConfirmDialog( |
| this, |
| "Credential Manager already contains a password entry with the same service URI.\n" |
| + "Do you want to overwrite it?", ALERT_TITLE, |
| YES_NO_OPTION); |
| |
| // Add the new password entry in the Keystore |
| try { |
| if (answer == YES_OPTION) { |
| credManager.addUsernameAndPasswordForService( |
| new UsernamePassword(username, password), |
| serviceURI); |
| break; |
| } |
| } catch (CMException cme) { |
| String exMessage = "Credential Manager failed to insert a new username and password pair"; |
| showMessageDialog(this, exMessage, ERROR_TITLE, |
| ERROR_MESSAGE); |
| } |
| // Otherwise show the same window with the entered service |
| // URI, username and password values |
| } else |
| // Add the new password entry in the Keystore |
| try { |
| credManager.addUsernameAndPasswordForService(new UsernamePassword(username, |
| password), serviceURI); |
| break; |
| } catch (CMException cme) { |
| showMessageDialog(this, "Credential Manager failed to insert a new username and password pair", |
| ERROR_TITLE, |
| ERROR_MESSAGE); |
| } |
| } |
| } |
| |
| /** |
| * Lets a user edit a username and password entry or their related service |
| * URI to the Keystore. |
| */ |
| private void editPassword() { |
| // Which password entry has been selected? |
| int iRow = passwordsTable.getSelectedRow(); |
| if (iRow == -1) { // no row currently selected |
| return; |
| } |
| |
| // Get current values for service URI, username and password |
| URI serviceURI = URI.create((String) passwordsTable.getValueAt(iRow, 1)); // current entry's service URI |
| |
| String username = (String) passwordsTable.getValueAt(iRow, 2); // current entry's username |
| |
| /* |
| * Because the password column is not visible we call the getValueAt |
| * method on the table model rather than at the JTable |
| */ |
| String password = (String) passwordsTable.getModel() |
| .getValueAt(iRow, 4); // current entry's password value |
| |
| while (true) { // loop until user cancels or enters everything correctly |
| // Let the user edit service URI, username or password of a password entry |
| NewEditPasswordEntryDialog editPasswordDialog = new NewEditPasswordEntryDialog( |
| this, "Edit username and password for a service", true, |
| serviceURI, username, password, credManager); |
| |
| editPasswordDialog.setLocationRelativeTo(this); |
| editPasswordDialog.setVisible(true); |
| |
| // New values |
| URI newServiceURI = editPasswordDialog.getServiceURI(); // get new service URI |
| String newUsername = editPasswordDialog.getUsername(); // get new username |
| String newPassword = editPasswordDialog.getPassword(); // get new password |
| |
| if (newPassword == null) // user cancelled - any of the above three |
| // fields is null |
| // do nothing |
| return; |
| |
| // Is anything actually modified? |
| boolean isModified = !serviceURI.equals(newServiceURI) |
| || !username.equals(newUsername) |
| || !password.equals(newPassword); |
| |
| if (isModified) { |
| /* |
| * Check if a different password entry with the new URI (i.e. |
| * alias) already exists in the Keystore We ask this here as the |
| * user may wish to overwrite that other password entry. |
| */ |
| |
| // Get list of URIs for all passwords in the Keystore |
| List<URI> serviceURIs = null; |
| try { |
| serviceURIs = credManager |
| .getServiceURIsForAllUsernameAndPasswordPairs(); |
| } catch (CMException cme) { |
| showMessageDialog(this, "Failed to get service URIs for all username and password pairs " |
| + "to check if the modified entry already exists", |
| ERROR_TITLE, |
| ERROR_MESSAGE); |
| return; |
| } |
| |
| // If the modified service URI already exists and is not the |
| // currently selected one |
| if (!newServiceURI.equals(serviceURI) |
| && serviceURIs.contains(newServiceURI)) { |
| int answer = showConfirmDialog( |
| this, |
| "The Keystore already contains username and password pair for the entered service URI.\n" |
| + "Do you want to overwrite it?", |
| ALERT_TITLE, YES_NO_OPTION); |
| |
| try { |
| if (answer == YES_OPTION) { |
| /* |
| * Overwrite that other entry entry and save the new |
| * one in its place. Also remove the current one |
| * that we are editing - as it is replacing the |
| * other entry. |
| */ |
| credManager |
| .deleteUsernameAndPasswordForService(serviceURI); |
| credManager.addUsernameAndPasswordForService( |
| new UsernamePassword(newUsername, |
| newPassword), newServiceURI); |
| break; |
| } |
| } catch (CMException cme) { |
| showMessageDialog( |
| this, |
| "Failed to update the username and password pair in the Keystore", |
| ERROR_TITLE, ERROR_MESSAGE); |
| } |
| // Otherwise show the same window with the entered |
| // service URI, username and password values |
| } else |
| try { |
| if (!newServiceURI.equals(serviceURI)) |
| credManager |
| .deleteUsernameAndPasswordForService(serviceURI); |
| credManager.addUsernameAndPasswordForService( |
| new UsernamePassword(newUsername, newPassword), newServiceURI); |
| break; |
| } catch (CMException cme) { |
| showMessageDialog( |
| this, |
| "Failed to update the username and password pair in the Keystore", |
| ERROR_TITLE, ERROR_MESSAGE); |
| } |
| } else // nothing actually modified |
| break; |
| } |
| } |
| |
| /** |
| * Lets the user delete the selected username and password entries from the |
| * Keystore. |
| */ |
| private void deletePassword() { |
| // Which entries have been selected? |
| int[] selectedRows = passwordsTable.getSelectedRows(); |
| if (selectedRows.length == 0) // no password entry selected |
| return; |
| |
| // Ask user to confirm the deletion |
| if (showConfirmDialog( |
| null, |
| "Are you sure you want to delete the selected username and password entries?", |
| ALERT_TITLE, YES_NO_OPTION) != YES_OPTION) |
| return; |
| |
| String exMessage = null; |
| for (int i = selectedRows.length - 1; i >= 0; i--) { // delete from backwards |
| // Get service URI for the current entry |
| URI serviceURI = URI.create((String) passwordsTable.getValueAt(selectedRows[i], 1)); |
| // current entry's service URI |
| try { |
| // Delete the password entry from the Keystore |
| credManager.deleteUsernameAndPasswordForService(serviceURI); |
| } catch (CMException cme) { |
| exMessage = "Failed to delete the username and password pair from the Keystore"; |
| } |
| } |
| if (exMessage != null) |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| |
| /** |
| * Shows the contents of a (user or trusted) certificate. |
| */ |
| private void viewCertificate() { |
| int selectedRow = -1; |
| String alias = null; |
| X509Certificate certToView = null; |
| ArrayList<String> serviceURIs = null; |
| KeystoreType keystoreType = null; |
| |
| // Are we showing user's public key certificate? |
| if (keyPairsTab.isShowing()) { |
| keystoreType = KEYSTORE; |
| selectedRow = keyPairsTable.getSelectedRow(); |
| |
| if (selectedRow != -1) |
| /* |
| * Because the alias column is not visible we call the |
| * getValueAt method on the table model rather than at the |
| * JTable |
| */ |
| alias = (String) keyPairsTable.getModel().getValueAt(selectedRow, 6); // current entry's Keystore alias |
| } |
| // Are we showing trusted certificate? |
| else if (trustedCertificatesTab.isShowing()) { |
| keystoreType = TRUSTSTORE; |
| selectedRow = trustedCertsTable.getSelectedRow(); |
| |
| if (selectedRow != -1) |
| /* |
| * Get the selected trusted certificate entry's Truststore alias |
| * Alias column is invisible so we get the value from the table |
| * model |
| */ |
| alias = (String) trustedCertsTable.getModel().getValueAt( |
| selectedRow, 5); |
| } |
| |
| try { |
| if (selectedRow != -1) { // something has been selected |
| // Get the entry's certificate |
| certToView = dnParser.convertCertificate(credManager |
| .getCertificate(keystoreType, alias)); |
| |
| // Show the certificate's contents to the user |
| ViewCertDetailsDialog viewCertDetailsDialog = new ViewCertDetailsDialog( |
| this, "Certificate details", true, certToView, |
| serviceURIs, dnParser); |
| viewCertDetailsDialog.setLocationRelativeTo(this); |
| viewCertDetailsDialog.setVisible(true); |
| } |
| } catch (CMException cme) { |
| String exMessage = "Failed to get certificate details to display to the user"; |
| logger.error(exMessage, cme); |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| } |
| |
| /** |
| * Lets a user import a key pair from a PKCS #12 keystore file to the |
| * Keystore. |
| */ |
| private void importKeyPair() { |
| /* |
| * Let the user choose a PKCS #12 file (keystore) containing a public |
| * and private key pair to import |
| */ |
| File importFile = selectImportExportFile( |
| "PKCS #12 file to import from", // title |
| new String[] { ".p12", ".pfx" }, // array of file extensions |
| // for the file filter |
| "PKCS#12 Files (*.p12, *.pfx)", // description of the filter |
| "Import", // text for the file chooser's approve button |
| "keyPairDir"); // preference string for saving the last chosen directory |
| |
| if (importFile == null) |
| return; |
| |
| // The PKCS #12 keystore is not a file |
| if (!importFile.isFile()) { |
| showMessageDialog(this, "Your selection is not a file", |
| ALERT_TITLE, WARNING_MESSAGE); |
| return; |
| } |
| |
| // Get the user to enter the password that was used to encrypt the |
| // private key contained in the PKCS #12 file |
| GetPasswordDialog getPasswordDialog = new GetPasswordDialog(this, |
| "Import key pair entry", true, |
| "Enter the password that was used to encrypt the PKCS #12 file"); |
| getPasswordDialog.setLocationRelativeTo(this); |
| getPasswordDialog.setVisible(true); |
| |
| String pkcs12Password = getPasswordDialog.getPassword(); |
| |
| if (pkcs12Password == null) // user cancelled |
| return; |
| else if (pkcs12Password.isEmpty()) // empty password |
| // FIXME: Maybe user did not have the password set for the private key??? |
| return; |
| |
| try { |
| // Load the PKCS #12 keystore from the file |
| // (this is using the BouncyCastle provider !!!) |
| KeyStore pkcs12Keystore = credManager.loadPKCS12Keystore(importFile, |
| pkcs12Password); |
| |
| /* |
| * Display the import key pair dialog supplying all the private keys |
| * stored in the PKCS #12 file (normally there will be only one |
| * private key inside, but could be more as this is a keystore after |
| * all). |
| */ |
| NewKeyPairEntryDialog importKeyPairDialog = new NewKeyPairEntryDialog( |
| this, "Credential Manager", true, pkcs12Keystore, dnParser); |
| importKeyPairDialog.setLocationRelativeTo(this); |
| importKeyPairDialog.setVisible(true); |
| |
| // Get the private key and certificate chain of the key pair |
| Key privateKey = importKeyPairDialog.getPrivateKey(); |
| Certificate[] certChain = importKeyPairDialog.getCertificateChain(); |
| |
| if (privateKey == null || certChain == null) |
| // User did not select a key pair for import or cancelled |
| return; |
| |
| /* |
| * Check if a key pair entry with the same alias already exists in |
| * the Keystore |
| */ |
| if (credManager.hasKeyPair(privateKey, certChain) |
| && showConfirmDialog(this, |
| "The keystore already contains the key pair entry with the same private key.\n" |
| + "Do you want to overwrite it?", |
| ALERT_TITLE, YES_NO_OPTION) != YES_OPTION) |
| return; |
| |
| // Place the private key and certificate chain into the Keystore |
| credManager.addKeyPair(privateKey, certChain); |
| |
| // Display success message |
| showMessageDialog(this, "Key pair import successful", ALERT_TITLE, |
| INFORMATION_MESSAGE); |
| } catch (Exception ex) { // too many exceptions to catch separately |
| String exMessage = "Failed to import the key pair entry to the Keystore. " |
| + ex.getMessage(); |
| logger.error(exMessage, ex); |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| } |
| |
| /** |
| * Lets a user export user's private and public key pair to a PKCS #12 |
| * keystore file. |
| */ |
| private void exportKeyPair() { |
| // Which key pair entry has been selected? |
| int selectedRow = keyPairsTable.getSelectedRow(); |
| if (selectedRow == -1) // no row currently selected |
| return; |
| |
| // Get the key pair entry's Keystore alias |
| String alias = (String) keyPairsTable.getModel().getValueAt(selectedRow, 6); |
| |
| // Let the user choose a PKCS #12 file (keystore) to export public and |
| // private key pair to |
| File exportFile = selectImportExportFile("Select a file to export to", // title |
| new String[] { ".p12", ".pfx" }, // array of file extensions |
| // for the file filter |
| "PKCS#12 Files (*.p12, *.pfx)", // description of the filter |
| "Export", // text for the file chooser's approve button |
| "keyPairDir"); // preference string for saving the last chosen directory |
| |
| if (exportFile == null) |
| return; |
| |
| // If file already exist - ask the user if he wants to overwrite it |
| if (exportFile.isFile() |
| && showConfirmDialog(this, |
| "The file with the given name already exists.\n" |
| + "Do you want to overwrite it?", ALERT_TITLE, |
| YES_NO_OPTION) == NO_OPTION) |
| return; |
| |
| // Get the user to enter the password for the PKCS #12 keystore file |
| GetPasswordDialog getPasswordDialog = new GetPasswordDialog(this, |
| "Credential Manager", true, |
| "Enter the password for protecting the exported key pair"); |
| getPasswordDialog.setLocationRelativeTo(this); |
| getPasswordDialog.setVisible(true); |
| |
| String pkcs12Password = getPasswordDialog.getPassword(); |
| |
| if (pkcs12Password == null) { // user cancelled or empty password |
| // Warn the user |
| showMessageDialog( |
| this, |
| "You must supply a password for protecting the exported key pair.", |
| ALERT_TITLE, INFORMATION_MESSAGE); |
| return; |
| } |
| |
| // Export the key pair |
| try { |
| credManager.exportKeyPair(alias, exportFile, pkcs12Password); |
| showMessageDialog(this, "Key pair export successful", ALERT_TITLE, |
| INFORMATION_MESSAGE); |
| } catch (CMException cme) { |
| showMessageDialog(this, cme.getMessage(), ERROR_TITLE, |
| ERROR_MESSAGE); |
| } |
| } |
| |
| /** |
| * Lets a user delete selected key pair entries from the Keystore. |
| */ |
| private void deleteKeyPair() { |
| // Which entries have been selected? |
| int[] selectedRows = keyPairsTable.getSelectedRows(); |
| if (selectedRows.length == 0) // no key pair entry selected |
| return; |
| |
| // Ask user to confirm the deletion |
| if (showConfirmDialog(null, |
| "Are you sure you want to delete the selected key pairs?", |
| ALERT_TITLE, YES_NO_OPTION) != YES_OPTION) |
| return; |
| |
| String exMessage = null; |
| for (int i = selectedRows.length - 1; i >= 0; i--) { // delete from backwards |
| // Get the alias for the current entry |
| String alias = (String) keyPairsTable.getModel().getValueAt( |
| selectedRows[i], 6); |
| try { |
| // Delete the key pair entry from the Keystore |
| credManager.deleteKeyPair(alias); |
| } catch (CMException cme) { |
| logger.warn("failed to delete " + alias, cme); |
| exMessage = "Failed to delete the key pair(s) from the Keystore"; |
| } |
| } |
| if (exMessage != null) |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| |
| /** |
| * Lets a user import a trusted certificate from a PEM or DER encoded file |
| * into the Truststore. |
| */ |
| private void importTrustedCertificate() { |
| // Let the user choose a file containing trusted certificate(s) to |
| // import |
| File certFile = selectImportExportFile( |
| "Certificate file to import from", // title |
| new String[] { ".pem", ".crt", ".cer", ".der", "p7", ".p7c" }, // file extensions filters |
| "Certificate Files (*.pem, *.crt, , *.cer, *.der, *.p7, *.p7c)", // filter descriptions |
| "Import", // text for the file chooser's approve button |
| "trustedCertDir"); // preference string for saving the last chosen directory |
| if (certFile == null) |
| return; |
| |
| // Load the certificate(s) from the file |
| ArrayList<X509Certificate> trustCertsList = new ArrayList<>(); |
| CertificateFactory cf; |
| try { |
| cf = CertificateFactory.getInstance("X.509"); |
| } catch (Exception e) { |
| // Nothing we can do! Things are badly misconfigured |
| cf = null; |
| } |
| |
| if (cf != null) { |
| try (FileInputStream fis = new FileInputStream(certFile)) { |
| for (Certificate cert : cf.generateCertificates(fis)) |
| trustCertsList.add((X509Certificate) cert); |
| } catch (Exception cex) { |
| // Do nothing |
| } |
| |
| if (trustCertsList.size() == 0) { |
| // Could not load certificates as any of the above types |
| try (FileInputStream fis = new FileInputStream(certFile); |
| PEMReader pr = new PEMReader( |
| new InputStreamReader(fis), null, cf |
| .getProvider().getName())) { |
| /* |
| * Try as openssl PEM format - which sligtly differs from |
| * the one supported by JCE |
| */ |
| Object cert; |
| while ((cert = pr.readObject()) != null) |
| if (cert instanceof X509Certificate) |
| trustCertsList.add((X509Certificate) cert); |
| } catch (Exception cex) { |
| // do nothing |
| } |
| } |
| } |
| |
| if (trustCertsList.size() == 0) { |
| /* Failed to load certifcate(s) using any of the known encodings */ |
| showMessageDialog(this, |
| "Failed to load certificate(s) using any of the known encodings -\n" |
| + "file format not recognised.", ERROR_TITLE, |
| ERROR_MESSAGE); |
| return; |
| } |
| |
| // Show the list of certificates contained in the file for the user to |
| // select the ones to import |
| NewTrustCertsDialog importTrustCertsDialog = new NewTrustCertsDialog(this, |
| "Credential Manager", true, trustCertsList, dnParser); |
| |
| importTrustCertsDialog.setLocationRelativeTo(this); |
| importTrustCertsDialog.setVisible(true); |
| List<X509Certificate> selectedTrustCerts = importTrustCertsDialog |
| .getTrustedCertificates(); // user-selected trusted certs to import |
| |
| // If user cancelled or did not select any cert to import |
| if (selectedTrustCerts == null || selectedTrustCerts.isEmpty()) |
| return; |
| |
| try { |
| for (X509Certificate cert : selectedTrustCerts) |
| // Import the selected trusted certificates |
| credManager.addTrustedCertificate(cert); |
| |
| // Display success message |
| showMessageDialog(this, "Trusted certificate(s) import successful", |
| ALERT_TITLE, INFORMATION_MESSAGE); |
| } catch (CMException cme) { |
| String exMessage = "Failed to import trusted certificate(s) to the Truststore"; |
| logger.error(exMessage, cme); |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| } |
| |
| /** |
| * Lets the user export one (at the moment) or more (in future) trusted |
| * certificate entries to a PEM-encoded file. |
| */ |
| private boolean exportTrustedCertificate() { |
| // Which trusted certificate has been selected? |
| int selectedRow = trustedCertsTable.getSelectedRow(); |
| if (selectedRow == -1) // no row currently selected |
| return false; |
| |
| // Get the trusted certificate entry's Keystore alias |
| String alias = (String) trustedCertsTable.getModel() |
| .getValueAt(selectedRow, 3); |
| // the alias column is invisible so we get the value from the table |
| // model |
| |
| // Let the user choose a file to export to |
| File exportFile = selectImportExportFile("Select a file to export to", // title |
| new String[] { ".pem" }, // array of file extensions for the |
| // file filter |
| "Certificate Files (*.pem)", // description of the filter |
| "Export", // text for the file chooser's approve button |
| "trustedCertDir"); // preference string for saving the last chosen directory |
| if (exportFile == null) |
| return false; |
| |
| // If file already exist - ask the user if he wants to overwrite it |
| if (exportFile.isFile() |
| && showConfirmDialog(this, |
| "The file with the given name already exists.\n" |
| + "Do you want to overwrite it?", ALERT_TITLE, |
| YES_NO_OPTION) == NO_OPTION) |
| return false; |
| |
| // Export the trusted certificate |
| try (PEMWriter pw = new PEMWriter(new FileWriter(exportFile))) { |
| // Get the trusted certificate |
| pw.writeObject(credManager.getCertificate(TRUSTSTORE, alias)); |
| } catch (Exception ex) { |
| String exMessage = "Failed to export the trusted certificate from the Truststore."; |
| logger.error(exMessage, ex); |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| return false; |
| } |
| showMessageDialog(this, "Trusted certificate export successful", |
| ALERT_TITLE, INFORMATION_MESSAGE); |
| return true; |
| } |
| |
| /** |
| * Lets a user delete the selected trusted certificate entries from the |
| * Truststore. |
| */ |
| private void deleteTrustedCertificate() { |
| // Which entries have been selected? |
| int[] selectedRows = trustedCertsTable.getSelectedRows(); |
| if (selectedRows.length == 0) // no trusted cert entry selected |
| return; |
| |
| // Ask user to confirm the deletion |
| if (showConfirmDialog( |
| null, |
| "Are you sure you want to delete the selected trusted certificate(s)?", |
| ALERT_TITLE, YES_NO_OPTION) != YES_OPTION) |
| return; |
| |
| String exMessage = null; |
| for (int i = selectedRows.length - 1; i >= 0; i--) { // delete from backwards |
| // Get the alias for the current entry |
| String alias = (String) trustedCertsTable.getModel().getValueAt( |
| selectedRows[i], 5); |
| try { |
| // Delete the trusted certificate entry from the Truststore |
| credManager.deleteTrustedCertificate(alias); |
| } catch (CMException cme) { |
| exMessage = "Failed to delete the trusted certificate(s) from the Truststore"; |
| logger.error(exMessage, cme); |
| } |
| } |
| if (exMessage != null) |
| showMessageDialog(this, exMessage, ERROR_TITLE, ERROR_MESSAGE); |
| } |
| |
| /** |
| * If double click on a table occured - show the |
| * details of the table entry. |
| */ |
| private void tableDoubleClick(MouseEvent evt) { |
| if (evt.getClickCount() > 1) { // is it a double click? |
| // Which row was clicked on (if any)? |
| Point point = new Point(evt.getX(), evt.getY()); |
| int row = ((JTable) evt.getSource()).rowAtPoint(point); |
| if (row == -1) |
| return; |
| // Which table the click occured on? |
| if (((JTable) evt.getSource()).getModel() instanceof PasswordsTableModel) |
| // Passwords table |
| viewPassword(); |
| else if (((JTable) evt.getSource()).getModel() instanceof KeyPairsTableModel) |
| // Key pairs table |
| viewCertificate(); |
| else |
| // Trusted certificates table |
| viewCertificate(); |
| } |
| } |
| |
| /** |
| * Lets the user select a file to export to or import from a key pair or a |
| * certificate. |
| */ |
| private File selectImportExportFile(String title, String[] filter, |
| String description, String approveButtonText, String prefString) { |
| Preferences prefs = Preferences |
| .userNodeForPackage(CredentialManagerUI.class); |
| String keyPairDir = prefs.get(prefString, |
| System.getProperty("user.home")); |
| JFileChooser fileChooser = new JFileChooser(); |
| fileChooser.addChoosableFileFilter(new CryptoFileFilter(filter, |
| description)); |
| fileChooser.setDialogTitle(title); |
| fileChooser.setMultiSelectionEnabled(false); |
| fileChooser.setCurrentDirectory(new File(keyPairDir)); |
| |
| if (fileChooser.showDialog(this, approveButtonText) != APPROVE_OPTION) |
| return null; |
| |
| File selectedFile = fileChooser.getSelectedFile(); |
| prefs.put(prefString, fileChooser.getCurrentDirectory().toString()); |
| return selectedFile; |
| } |
| |
| private void closeFrame() { |
| setVisible(false); |
| dispose(); |
| } |
| } |