blob: 36e3015598a4ba652914cfe332c32c27ce86e05e [file] [log] [blame]
/*******************************************************************************
* 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.SOUTH;
import static java.awt.BorderLayout.WEST;
import static java.awt.Font.PLAIN;
import static javax.swing.BoxLayout.Y_AXIS;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog;
import static javax.swing.ListSelectionModel.SINGLE_SELECTION;
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
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.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.sf.taverna.t2.security.credentialmanager.CMException;
import net.sf.taverna.t2.security.credentialmanager.DistinguishedNameParser;
import net.sf.taverna.t2.workbench.helper.NonBlockedHelpEnabledDialog;
/**
* Allows the user import a key pair from a PKCS #12 file (keystore).
*/
@SuppressWarnings("serial")
class NewKeyPairEntryDialog extends NonBlockedHelpEnabledDialog {
//private static final Logger logger = Logger.getLogger(NewKeyPairEntryDialog.class);
/** List of key pairs available for import */
private JList<String> keyPairsJList;
/** PKCS #12 keystore */
private KeyStore pkcs12KeyStore;
/** Private key part of the key pair chosen by the user for import */
private Key privateKey;
/** Certificate chain part of the key pair chosen by the user for import */
private Certificate[] certificateChain;
/** Key pair alias to be used for this entry in the Keystore */
private String alias;
private final DistinguishedNameParser dnParser;
public NewKeyPairEntryDialog(JFrame parent, String title, boolean modal,
KeyStore pkcs12KeyStore, DistinguishedNameParser dnParser)
throws CMException {
super(parent, title, modal);
this.pkcs12KeyStore = pkcs12KeyStore;
this.dnParser = dnParser;
initComponents();
}
public NewKeyPairEntryDialog(JDialog parent, String title, boolean modal,
KeyStore pkcs12KeyStore, DistinguishedNameParser dnParser)
throws CMException {
super(parent, title, modal);
this.pkcs12KeyStore = pkcs12KeyStore;
this.dnParser = dnParser;
initComponents();
}
/**
* Get the private part of the key pair.
*/
public Key getPrivateKey() {
return privateKey;
}
/**
* Get the certificate chain part of the key pair.
*/
public Certificate[] getCertificateChain() {
return certificateChain;
}
/**
* Get the keystore alias of the key pair.
*/
public String getAlias() {
return alias;
}
private void initComponents() throws CMException {
// Instructions
JLabel instructionsLabel = new JLabel("Select a key pair to import:");
instructionsLabel.setFont(new Font(null, PLAIN, 11));
instructionsLabel.setBorder(new EmptyBorder(5, 5, 5, 5));
JPanel instructionsPanel = new JPanel(new BorderLayout());
instructionsPanel.add(instructionsLabel, WEST);
// Import button
final JButton importButton = new JButton("Import");
importButton.setEnabled(false);
importButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
importPressed();
}
});
// Certificate details button
final JButton certificateDetailsButton = new JButton("Details");
certificateDetailsButton.setEnabled(false);
certificateDetailsButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
certificateDetailsPressed();
}
});
// List to hold keystore's key pairs
keyPairsJList = new JList<>();
keyPairsJList.setSelectionMode(SINGLE_SELECTION);
keyPairsJList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent evt) {
boolean enabled = keyPairsJList.getSelectedIndex() >= 0;
importButton.setEnabled(enabled);
certificateDetailsButton.setEnabled(enabled);
}
});
// Put the key list into a scroll pane
JScrollPane keyPairsScrollPane = new JScrollPane(keyPairsJList,
VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
keyPairsScrollPane.getViewport().setBackground(
keyPairsJList.getBackground());
JPanel keyPairsPanel = new JPanel();
keyPairsPanel.setLayout(new BoxLayout(keyPairsPanel, Y_AXIS));
keyPairsPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
instructionsPanel.setAlignmentY(LEFT_ALIGNMENT);
keyPairsPanel.add(instructionsPanel);
keyPairsScrollPane.setAlignmentY(LEFT_ALIGNMENT);
keyPairsPanel.add(keyPairsScrollPane);
// Cancel button
final JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
cancelPressed();
}
});
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
buttonsPanel.add(certificateDetailsButton);
buttonsPanel.add(importButton);
buttonsPanel.add(cancelButton);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(keyPairsPanel, CENTER);
getContentPane().add(buttonsPanel, SOUTH);
// Populate the list
populateKeyPairList();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
closeDialog();
}
});
setResizable(false);
getRootPane().setDefaultButton(importButton);
pack();
}
/**
* Populate the key pair list with the PKCS #12 keystore's key pair aliases.
*/
private void populateKeyPairList() throws CMException {
try {
List<String> keyPairAliases = new ArrayList<>();
Enumeration<String> aliases = pkcs12KeyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (pkcs12KeyStore.isKeyEntry(alias)) {
pkcs12KeyStore.getKey(alias, new char[] {});
Certificate[] certs = pkcs12KeyStore
.getCertificateChain(alias);
if (certs != null && certs.length != 0)
keyPairAliases.add(alias);
}
}
if (!keyPairAliases.isEmpty()) {
keyPairsJList.setListData(keyPairAliases.toArray(new String[0]));
keyPairsJList.setSelectedIndex(0);
} else
// No key pairs were found - warn the user
showMessageDialog(this,
"No private key pairs were found in the file",
ALERT_TITLE, WARNING_MESSAGE);
} catch (GeneralSecurityException ex) {
throw new CMException("Problem occured while reading the PKCS #12 file.",
ex);
}
}
/**
* Display the selected key pair's certificate.
*/
private void certificateDetailsPressed() {
try {
String alias = (String) keyPairsJList.getSelectedValue();
// Convert the certificate object into an X509Certificate object.
X509Certificate cert = dnParser.convertCertificate(pkcs12KeyStore
.getCertificate(alias));
ViewCertDetailsDialog viewCertificateDialog = new ViewCertDetailsDialog(
this, "Certificate details", true, (X509Certificate) cert,
null, dnParser);
viewCertificateDialog.setLocationRelativeTo(this);
viewCertificateDialog.setVisible(true);
} catch (Exception ex) {
showMessageDialog(this,
"Failed to obtain certificate details to show",
ALERT_TITLE, WARNING_MESSAGE);
closeDialog();
}
}
public void importPressed() {
String alias = (String) keyPairsJList.getSelectedValue();
try {
privateKey = pkcs12KeyStore.getKey(alias, new char[] {});
certificateChain = pkcs12KeyStore.getCertificateChain(alias);
this.alias = alias;
} catch (Exception ex) {
showMessageDialog(
this,
"Failed to load the private key and certificate chain from the PKCS #12 file.",
ERROR_TITLE, ERROR_MESSAGE);
}
closeDialog();
}
public void cancelPressed() {
/*
* Set everything to null, just in case some of the values have been set
* previously and the user pressed 'cancel' after that.
*/
privateKey = null;
certificateChain = null;
closeDialog();
}
private void closeDialog() {
setVisible(false);
dispose();
}
}