You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by re...@apache.org on 2015/03/26 19:52:22 UTC

[33/51] [partial] incubator-taverna-workbench git commit: all packages are moved to org.apache.taverna.*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ChangeMasterPasswordDialog.java
----------------------------------------------------------------------
diff --git a/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ChangeMasterPasswordDialog.java b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ChangeMasterPasswordDialog.java
new file mode 100644
index 0000000..686ebc1
--- /dev/null
+++ b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ChangeMasterPasswordDialog.java
@@ -0,0 +1,233 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.credentialmanager;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.BorderLayout.SOUTH;
+import static java.awt.Font.PLAIN;
+import static javax.swing.BoxLayout.Y_AXIS;
+import static javax.swing.JOptionPane.WARNING_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.taverna.workbench.ui.credentialmanager.CMStrings.WARN_TITLE;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+import org.apache.taverna.workbench.helper.NonBlockedHelpEnabledDialog;
+
+/**
+ * Dialog used by users to change their master password for the Credential
+ * Manager.
+ */
+@SuppressWarnings("serial")
+public class ChangeMasterPasswordDialog extends NonBlockedHelpEnabledDialog {
+	/** Old password entry field */
+	private JPasswordField oldPasswordField;
+	/** New password entry field */
+	private JPasswordField newPasswordField;
+	/** New password confirmation entry field */
+	private JPasswordField newPasswordConfirmField;
+	/** The entered new password */
+	private String password = null;
+	/** Instructions to the users as to what to do in the dialog */
+	private String instructions;
+	private final CredentialManager credentialManager;
+
+	public ChangeMasterPasswordDialog(JFrame parent, String title,
+			boolean modal, String instructions,
+			CredentialManager credentialManager) {
+		super(parent, title, modal, null);
+		this.instructions = instructions;
+		this.credentialManager = credentialManager;
+		initComponents();
+	}
+
+	private void initComponents() {
+		getContentPane().setLayout(new BorderLayout());
+
+		JLabel instructionsLabel = new JLabel(instructions);
+		instructionsLabel.setFont(new Font(null, PLAIN, 11));
+
+		JPanel instructionsPanel = new JPanel();
+		instructionsPanel.setLayout(new BoxLayout(instructionsPanel, Y_AXIS));
+		instructionsPanel.add(instructionsLabel);
+		instructionsPanel.setBorder(new EmptyBorder(10, 5, 10, 0));
+
+		JLabel oldPasswordLabel = new JLabel("Old master password");
+		oldPasswordLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
+
+		JLabel newPasswordLabel = new JLabel("New master password");
+		newPasswordLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
+
+		JLabel newPasswordConfirmLabel = new JLabel(
+				"Confirm new master password");
+		newPasswordConfirmLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
+
+		oldPasswordField = new JPasswordField(15);
+		newPasswordField = new JPasswordField(15);
+		newPasswordConfirmField = new JPasswordField(15);
+
+		JPanel jpPassword = new JPanel(new GridLayout(0, 2, 5, 5));
+		jpPassword.add(oldPasswordLabel);
+		jpPassword.add(oldPasswordField);
+		jpPassword.add(newPasswordLabel);
+		jpPassword.add(newPasswordField);
+		jpPassword.add(newPasswordConfirmLabel);
+		jpPassword.add(newPasswordConfirmField);
+
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10),
+				new EtchedBorder()));
+		mainPanel.add(instructionsPanel, NORTH);
+		mainPanel.add(jpPassword, CENTER);
+
+		JButton okButton = new JButton("OK");
+		okButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent evt) {
+				okPressed();
+			}
+		});
+
+		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(okButton);
+		buttonsPanel.add(cancelButton);
+
+		getContentPane().add(mainPanel, CENTER);
+		getContentPane().add(buttonsPanel, SOUTH);
+
+		addWindowListener(new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				closeDialog();
+			}
+		});
+
+		setResizable(false);
+		getRootPane().setDefaultButton(okButton);
+		pack();
+	}
+
+	/**
+	 * Get the password set in the dialog or null if none was set.
+	 */
+	public String getPassword() {
+		return password;
+	}
+
+	/**
+	 * Check that the user has provided the correct old master password, that
+	 * the user has supplied the new password and confirmed it and that it is
+	 * not empty. If all is OK, stores the new password in the password field.
+	 * 
+	 */
+	private boolean checkPassword() {
+		String oldPassword = new String(oldPasswordField.getPassword());
+
+		if (oldPassword.length() == 0) {
+			// old password must not be empty
+			showMessageDialog(this,
+					"You must provide your current master password",
+					WARN_TITLE, WARNING_MESSAGE);
+			return false;
+		}
+
+		try {
+			if (!credentialManager.confirmMasterPassword(oldPassword)) {
+				showMessageDialog(this,
+						"You have provided an incorrect master password",
+						WARN_TITLE, WARNING_MESSAGE);
+				return false;
+			}
+		} catch (Exception e) {
+			showMessageDialog(
+					this,
+					"Credential Manager could not verify your current master password",
+					WARN_TITLE, WARNING_MESSAGE);
+			return false;
+		}
+
+		String newPassword = new String(newPasswordField.getPassword());
+		String newPasswordConfirm = new String(
+				newPasswordConfirmField.getPassword());
+
+		if (!newPassword.equals(newPasswordConfirm)) {
+			// passwords do not match
+			showMessageDialog(this, "Passwords do not match", WARN_TITLE,
+					WARNING_MESSAGE);
+			return false;
+		}
+
+		if (newPassword.isEmpty()) {
+			// passwords match but are empty
+			showMessageDialog(this, "The new master password cannot be empty",
+					WARN_TITLE, WARNING_MESSAGE);
+			return false;
+		}
+
+		// passwords match and not empty
+		password = newPassword;
+		return true;
+	}
+
+	private void okPressed() {
+		if (checkPassword())
+			closeDialog();
+	}
+
+	private void cancelPressed() {
+		/*
+		 * Set the password to null as it might have changed in the meantime if
+		 * user entered something then cancelled.
+		 */
+		password = null;
+		closeDialog();
+	}
+
+	private void closeDialog() {
+		setVisible(false);
+		dispose();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateDialog.java
----------------------------------------------------------------------
diff --git a/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateDialog.java b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateDialog.java
new file mode 100644
index 0000000..c725983
--- /dev/null
+++ b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateDialog.java
@@ -0,0 +1,519 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.credentialmanager;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.BorderLayout.SOUTH;
+import static java.awt.Color.WHITE;
+import static java.awt.Font.BOLD;
+import static java.awt.Font.PLAIN;
+import static java.awt.GridBagConstraints.LINE_START;
+import static javax.security.auth.x500.X500Principal.RFC2253;
+
+import java.awt.BorderLayout;
+import java.awt.Dialog;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.math.BigInteger;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+
+import org.apache.taverna.lang.ui.DialogTextArea;
+import org.apache.taverna.security.credentialmanager.CMException;
+import org.apache.taverna.security.credentialmanager.DistinguishedNameParser;
+import org.apache.taverna.security.credentialmanager.ParsedDistinguishedName;
+import org.apache.taverna.workbench.helper.NonBlockedHelpEnabledDialog;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Displays the details of a X.509 certificate and asks user if they want to
+ * trust it. This is normally invoked by the Taverna's TrustManager when trying 
+ * to confirm the trust in the remote server during SSL handshake.
+ */
+@SuppressWarnings("serial")
+public class ConfirmTrustedCertificateDialog extends NonBlockedHelpEnabledDialog {
+	private static Logger logger = Logger.getLogger(ConfirmTrustedCertificateDialog.class);
+
+	/** The certificate to display */
+	private X509Certificate cert;
+	/** User's decision as whether to trust this service's certificate or not */
+	private boolean shouldTrust;
+	/**
+	 * Should the decision also be saved in Credential Manager? Actually - it is
+	 * always saved now as it was really hard to implement trusting for one
+	 * connection only - so we can either "trust" or "not" trust but not
+	 * "trust once".
+	 */
+	private boolean shouldSave = false;
+	private final DistinguishedNameParser dnParser;
+
+	public ConfirmTrustedCertificateDialog(Frame parent, String title,
+			boolean modal, X509Certificate crt, DistinguishedNameParser dnParser) {
+		super(parent, title, modal);
+		this.cert = crt;
+		this.dnParser = dnParser;
+		initComponents();
+	}
+
+	public ConfirmTrustedCertificateDialog(Dialog parent, String title,
+			boolean modal, X509Certificate crt, DistinguishedNameParser dnParser)
+			throws CMException {
+		super(parent, title, modal);
+		this.cert = crt;
+		this.dnParser = dnParser;
+		initComponents();
+	}
+
+	private void initComponents(){		
+		// title panel
+		JPanel titlePanel = new JPanel(new BorderLayout());
+		titlePanel.setBackground(WHITE);
+		JLabel titleLabel = new JLabel("View service's certificate");
+		titleLabel.setFont(titleLabel.getFont().deriveFont(BOLD, 13.5f));
+		titleLabel.setBorder(new EmptyBorder(10, 10, 0, 10));
+
+		DialogTextArea titleMessage = new DialogTextArea();
+		titleMessage.setMargin(new Insets(5, 20, 10, 10));
+		titleMessage.setFont(titleMessage.getFont().deriveFont(11f));
+		titleMessage.setEditable(false);
+		titleMessage.setFocusable(false);
+		titlePanel.setBorder( new EmptyBorder(10, 10, 0, 10));
+		titlePanel.add(titleLabel, NORTH);
+		titlePanel.add(titleMessage, CENTER);
+		
+		// Certificate details:
+
+		ParsedDistinguishedName subjectDN = dnParser.parseDN(cert
+				.getSubjectX500Principal().getName(RFC2253));
+		ParsedDistinguishedName issuerDN = dnParser.parseDN(cert
+				.getIssuerX500Principal().getName(RFC2253));
+		JPanel certificatePanel = createCertificateDetailsPanel(subjectDN, issuerDN);
+		titleMessage.setText("The service host " + subjectDN.getCN() + " requires HTTPS connection and has identified itself with the certificate below.\n" +
+				"Do you want to trust this service? (Refusing to trust means you will not be able to invoke services on this host from a workflow.)");
+
+		// OK button
+		JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+
+//		final JButton trustButton = new JButton("Trust once");
+//		trustButton.addActionListener(new ActionListener() {
+//			public void actionPerformed(ActionEvent evt) {
+//				trustPressed();
+//			}
+//		});
+		
+		//final JButton trustAlwaysButton = new JButton("Trust always");
+		final JButton trustAlwaysButton = new JButton("Trust");
+		trustAlwaysButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent evt) {
+				trustAlwaysPressed();
+			}
+		});
+		
+		final JButton dontTrustButton = new JButton("Do not trust");
+		dontTrustButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent evt) {
+				dontTrustPressed();
+			}
+		});
+
+		//jpButtons.add(trustButton);
+		buttonsPanel.add(trustAlwaysButton);
+		buttonsPanel.add(dontTrustButton);
+
+		getContentPane().add(titlePanel, NORTH);
+		getContentPane().add(certificatePanel, CENTER);
+		getContentPane().add(buttonsPanel, SOUTH);
+
+		setResizable(false);
+
+		addWindowListener(new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent evt) {
+				closeDialog();
+			}
+		});
+
+		getRootPane().setDefaultButton(trustAlwaysButton);
+		pack();
+	}
+
+	private JPanel createCertificateDetailsPanel(ParsedDistinguishedName subjectDN, ParsedDistinguishedName issuerDN) {
+		/*
+		 * Grid Bag Constraints templates for labels (column 1) and values
+		 * (column 2) of certificate details
+		 */
+		GridBagConstraints gbc_labels = new GridBagConstraints();
+		gbc_labels.gridx = 0;
+		gbc_labels.ipadx = 20;
+		gbc_labels.gridwidth = 1;
+		gbc_labels.gridheight = 1;
+		gbc_labels.insets = new Insets(2, 15, 2, 2);
+		gbc_labels.anchor = LINE_START;
+
+		GridBagConstraints gbc_values = new GridBagConstraints();
+		gbc_values.gridx = 1;
+		gbc_values.gridwidth = 1;
+		gbc_values.gridheight = 1;
+		gbc_values.insets = new Insets(2, 5, 2, 2);
+		gbc_values.anchor = LINE_START;
+
+		/*
+		 * Netscape Certificate Type non-critical extension (if any) defines the
+		 * intended uses of the certificate - to make it look like Firefox's
+		 * view certificate dialog
+		 * 
+		 * From openssl's documentation: "The [above] extension is non standard,
+		 * Netscape specific and largely obsolete. Their use in new applications
+		 * is discouraged."
+		 * 
+		 * TODO replace with "basicConstraints, keyUsage and extended key usage
+		 * extensions which are now used instead."
+		 */
+//		byte[] intendedUses = cert.getExtensionValue("2.16.840.1.113730.1.1"); // Netscape Certificate Type OID
+//		JLabel intendedUsesLabel = null;
+//		JTextField intendedUsesTextField = null;
+//		JPanel intendedUsesPanel = null;
+//		GridBagConstraints gbc_intendedUsesLabel = null;
+//		if (intendedUses != null) {
+//			intendedUsesLabel = new JLabel(
+//					"This certificate has been approved for the following uses:");
+//			intendedUsesLabel.setFont(new Font(null, Font.BOLD, 11));
+//			intendedUsesLabel.setBorder(new EmptyBorder(5, 5, 5, 5));
+//
+//			intendedUsesTextField = new JTextField(45);
+//			intendedUsesTextField.setText(CMUtils.getIntendedCertificateUses(intendedUses));
+//			intendedUsesTextField.setEditable(false);
+//			intendedUsesTextField.setFont(new Font(null, Font.PLAIN, 11));
+//
+//			intendedUsesPanel = new JPanel(new BorderLayout());
+//			intendedUsesPanel.add(intendedUsesLabel, BorderLayout.NORTH);
+//			intendedUsesPanel.add(intendedUsesTextField, BorderLayout.CENTER);
+//			JSeparator separator = new JSeparator(JSeparator.HORIZONTAL);
+//			intendedUsesPanel.add(separator, BorderLayout.SOUTH);
+//
+//			gbc_intendedUsesLabel = (GridBagConstraints) gbc_labels.clone();
+//			gbc_intendedUsesLabel.gridy = 0;
+//			gbc_intendedUsesLabel.gridwidth = 2; // takes two columns
+//			gbc_intendedUsesLabel.insets = new Insets(5, 5, 5, 5);// has slightly bigger insets
+//		}
+
+		// Issued To
+		JLabel issuedToLabel = new JLabel("Issued To");
+		issuedToLabel.setFont(new Font(null, BOLD, 11));
+		GridBagConstraints gbc_issuedTo = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_issuedTo.gridy = 1;
+		gbc_issuedTo.gridwidth = 2; // takes two columns
+		gbc_issuedTo.insets = new Insets(5, 5, 5, 5);// has slightly bigger insets
+		// Subject's Distinguished Name (DN)
+		// Extract the CN, O, OU and EMAILADDRESS fields
+		String subjectCN = subjectDN.getCN();
+		String subjectOrg = subjectDN.getO();
+		String subjectOU = subjectDN.getOU();
+		// String sEMAILADDRESS = CMUtils.getEmilAddress();
+		// Subject's Common Name (CN)
+		JLabel subjectCNLabel = new JLabel("Common Name (CN)");
+		subjectCNLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_subjectCNLabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_subjectCNLabel.gridy = 2;
+		JLabel subjectCNValue = new JLabel(subjectCN);
+		subjectCNValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_subjectCNValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_subjectCNValue.gridy = 2;
+		// Subject's Organisation (O)
+		JLabel subjectOrgLabel = new JLabel("Organisation (O)");
+		subjectOrgLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_subjectOrgLabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_subjectOrgLabel.gridy = 3;
+		JLabel subjectOrgValue = new JLabel(subjectOrg);
+		subjectOrgValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_subjectOrgValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_subjectOrgValue.gridy = 3;
+		// Subject's Organisation Unit (OU)
+		JLabel subjectOULabel = new JLabel("Organisation Unit (OU)");
+		subjectOULabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_subjectOULabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_subjectOULabel.gridy = 4;
+		JLabel subjectOUValue = new JLabel(subjectOU);
+		subjectOUValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_subjectOUValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_subjectOUValue.gridy = 4;
+		// E-mail Address
+		// JLabel jlEmail = new JLabel("E-mail Address");
+		// jlEmail.setFont(new Font(null, Font.PLAIN, 11));
+		// GridBagConstraints gbc_jlEmail = (GridBagConstraints)
+		// gbcLabel.clone();
+		// gbc_jlEmail.gridy = 5;
+		// JLabel jlEmailValue = new JLabel(sEMAILADDRESS);
+		// jlEmailValue.setFont(new Font(null, Font.PLAIN, 11));
+		// GridBagConstraints gbc_jlEmailValue = (GridBagConstraints)
+		// gbcValue.clone();
+		// gbc_jlEmailValue.gridy = 5;
+		// Serial Number
+		JLabel snLabel = new JLabel("Serial Number");
+		snLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_snLabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_snLabel.gridy = 6;
+		JLabel snValue = new JLabel();
+		// Get the hexadecimal serial number
+		StringBuilder strBuff = new StringBuilder(new BigInteger(1, cert
+				.getSerialNumber().toByteArray()).toString(16).toUpperCase());
+		// Place colons at every two hexadecimal characters
+		if (strBuff.length() > 2)
+			for (int iCnt = 2; iCnt < strBuff.length(); iCnt += 3)
+				strBuff.insert(iCnt, ':');
+		snValue.setText(strBuff.toString());
+		snValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_snValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_snValue.gridy = 6;
+		// Certificate version number
+		JLabel versionLabel = new JLabel("Version");
+		versionLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_versionLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_versionLabel.gridy = 7;
+		JLabel versionValue = new JLabel(Integer.toString(cert.getVersion()));
+		versionValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_versionValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_versionValue.gridy = 7;
+
+		// Issued By
+		JLabel issuedByLabel = new JLabel("Issued By");
+		issuedByLabel.setFont(new Font(null, BOLD, 11));
+		GridBagConstraints gbc_issuedByLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_issuedByLabel.gridy = 8;
+		gbc_issuedByLabel.gridwidth = 2; // takes two columns
+		gbc_issuedByLabel.insets = new Insets(5, 5, 5, 5);// has slightly bigger insets
+		// Issuer's Distinguished Name (DN)
+		// Extract the CN, O and OU fields for the issuer
+		String issuerCN = issuerDN.getCN();
+		String issuerOrg = issuerDN.getO();
+		String issuerOU = issuerDN.getOU();
+		// Issuer's Common Name (CN)
+		JLabel issuerCNLabel = new JLabel("Common Name (CN)");
+		issuerCNLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuerCNLabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_issuerCNLabel.gridy = 9;
+		JLabel issuerCNValue = new JLabel(issuerCN);
+		issuerCNValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuerCNValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_issuerCNValue.gridy = 9;
+		// Issuer's Organisation (O)
+		JLabel issuerOrgLabel = new JLabel("Organisation (O)");
+		issuerOrgLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuerOrgLabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_issuerOrgLabel.gridy = 10;
+		JLabel issuerOrgValue = new JLabel(issuerOrg);
+		issuerOrgValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuerOrgValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_issuerOrgValue.gridy = 10;
+		// Issuer's Organisation Unit (OU)
+		JLabel issuerOULabel = new JLabel("Organisation Unit (OU)");
+		issuerOULabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuerOULabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_issuerOULabel.gridy = 11;
+		JLabel issuerOUValue = new JLabel(issuerOU);
+		issuerOUValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuerOUValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_issuerOUValue.gridy = 11;
+		
+		// Validity
+		JLabel validityLabel = new JLabel("Validity");
+		validityLabel.setFont(new Font(null, BOLD, 11));
+		GridBagConstraints gbc_validityLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_validityLabel.gridy = 12;
+		gbc_validityLabel.gridwidth = 2; // takes two columns
+		gbc_validityLabel.insets = new Insets(5, 5, 5, 5);// has slightly bigger insets
+		// Issued On
+		JLabel issuedOnLabel = new JLabel("Issued On");
+		issuedOnLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuedOnLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_issuedOnLabel.gridy = 13;
+		JLabel issuedOnValue = new JLabel(cert.getNotBefore().toString());
+		issuedOnValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_issuedOnValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_issuedOnValue.gridy = 13;
+		// Expires On
+		JLabel expiresOnLabel = new JLabel("Expires On");
+		expiresOnLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_expiresOnLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_expiresOnLabel.gridy = 14;
+		JLabel expiresOnValue = new JLabel(cert.getNotAfter().toString());
+		expiresOnValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_expiresOnValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_expiresOnValue.gridy = 14;
+
+		// Fingerprints
+		byte[] binaryCertificateEncoding = new byte[0];
+		try {
+			// each certificate has one binary encoding; for X.509 certs it is DER
+			binaryCertificateEncoding = cert.getEncoded();
+		} catch (CertificateEncodingException ex) {
+			logger.error("Could not get the encoded form of the certificate.", ex);
+		}
+		JLabel fingerprintsLabel = new JLabel("Fingerprints");
+		fingerprintsLabel.setFont(new Font(null, BOLD, 11));
+		GridBagConstraints gbc_fingerprintsLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_fingerprintsLabel.gridy = 15;
+		gbc_fingerprintsLabel.gridwidth = 2; // takes two columns
+		gbc_fingerprintsLabel.insets = new Insets(5, 5, 5, 5);// has slightly bigger insets
+		// SHA-1 Fingerprint
+		JLabel sha1FingerprintLabel = new JLabel("SHA1 Fingerprint");
+		sha1FingerprintLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_sha1FingerprintLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_sha1FingerprintLabel.gridy = 16;
+		JLabel sha1FingerprintValue = new JLabel(
+				dnParser.getMessageDigestAsFormattedString(
+						binaryCertificateEncoding, "SHA1"));
+		sha1FingerprintValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_sha1FingerprintValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_sha1FingerprintValue.gridy = 16;
+		// MD5 Fingerprint
+		JLabel md5FingerprintLabel = new JLabel("MD5 Fingerprint");
+		md5FingerprintLabel.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_md5FingerprinLabel = (GridBagConstraints) gbc_labels
+				.clone();
+		gbc_md5FingerprinLabel.gridy = 17;
+		JLabel md5FingerprintValue = new JLabel(
+				dnParser.getMessageDigestAsFormattedString(
+						binaryCertificateEncoding, "MD5"));
+		md5FingerprintValue.setFont(new Font(null, PLAIN, 11));
+		GridBagConstraints gbc_md5FingerprintValue = (GridBagConstraints) gbc_values
+				.clone();
+		gbc_md5FingerprintValue.gridy = 17;
+
+		/*
+		 * Empty label to add a bit space at the bottom of the panel to make it
+		 * look like Firefox's view certificate dialog
+		 */
+		JLabel emptyLabel = new JLabel("");
+		GridBagConstraints gbc_emptyLabel = (GridBagConstraints) gbc_labels.clone();
+		gbc_emptyLabel.gridy = 18;
+		gbc_emptyLabel.gridwidth = 2; // takes two columns
+		gbc_emptyLabel.ipady = 40;
+
+		JPanel certificatePanel = new JPanel(new GridBagLayout());
+		certificatePanel.setBorder(new CompoundBorder(new EmptyBorder(15, 15, 15,
+				15), new EtchedBorder()));
+
+//		if (intendedUses != null)
+//			certificatePanel.add(intendedUsesPanel, gbc_intendedUsesLabel);
+		certificatePanel.add(issuedToLabel, gbc_issuedTo); // Issued To
+		certificatePanel.add(subjectCNLabel, gbc_subjectCNLabel);
+		certificatePanel.add(subjectCNValue, gbc_subjectCNValue);
+		certificatePanel.add(subjectOrgLabel, gbc_subjectOrgLabel);
+		certificatePanel.add(subjectOrgValue, gbc_subjectOrgValue);
+		certificatePanel.add(subjectOULabel, gbc_subjectOULabel);
+		certificatePanel.add(subjectOUValue, gbc_subjectOUValue);
+		// jpCertificate.add(jlEmail, gbc_jlEmail);
+		// jpCertificate.add(jlEmailValue, gbc_jlEmailValue);
+		certificatePanel.add(snLabel, gbc_snLabel);
+		certificatePanel.add(snValue, gbc_snValue);
+		certificatePanel.add(versionLabel, gbc_versionLabel);
+		certificatePanel.add(versionValue, gbc_versionValue);
+		certificatePanel.add(issuedByLabel, gbc_issuedByLabel); // Issued By
+		certificatePanel.add(issuerCNLabel, gbc_issuerCNLabel);
+		certificatePanel.add(issuerCNValue, gbc_issuerCNValue);
+		certificatePanel.add(issuerOrgLabel, gbc_issuerOrgLabel);
+		certificatePanel.add(issuerOrgValue, gbc_issuerOrgValue);
+		certificatePanel.add(issuerOULabel, gbc_issuerOULabel);
+		certificatePanel.add(issuerOUValue, gbc_issuerOUValue);
+		certificatePanel.add(validityLabel, gbc_validityLabel); // Validity
+		certificatePanel.add(issuedOnLabel, gbc_issuedOnLabel);
+		certificatePanel.add(issuedOnValue, gbc_issuedOnValue);
+		certificatePanel.add(expiresOnLabel, gbc_expiresOnLabel);
+		certificatePanel.add(expiresOnValue, gbc_expiresOnValue);
+		certificatePanel.add(fingerprintsLabel, gbc_fingerprintsLabel); // Fingerprints
+		certificatePanel.add(sha1FingerprintLabel, gbc_sha1FingerprintLabel);
+		certificatePanel.add(sha1FingerprintValue, gbc_sha1FingerprintValue);
+		certificatePanel.add(md5FingerprintLabel, gbc_md5FingerprinLabel);
+		certificatePanel.add(md5FingerprintValue, gbc_md5FingerprintValue);
+		// Empty label to get some vertical space on the frame
+		certificatePanel.add(emptyLabel, gbc_emptyLabel);
+		return certificatePanel;
+	}
+
+//	private void trustPressed() {
+//		shouldTrust = true;
+//		shouldSave = false;
+//		closeDialog();
+//	}
+
+	private void trustAlwaysPressed() {
+		shouldTrust = true;
+		shouldSave = true;
+		closeDialog();
+	}
+
+	private void dontTrustPressed() {
+		shouldTrust = false;
+		shouldSave = false;
+		closeDialog();
+	}
+
+	public void closeDialog() {
+		setVisible(false);
+		dispose();
+	}
+
+	public boolean shouldTrust() {
+		return shouldTrust;
+	}
+
+	public boolean shouldSave() {
+		return shouldSave;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateUI.java
----------------------------------------------------------------------
diff --git a/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateUI.java b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateUI.java
new file mode 100644
index 0000000..1207a73
--- /dev/null
+++ b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/ConfirmTrustedCertificateUI.java
@@ -0,0 +1,70 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.credentialmanager;
+
+import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+
+import java.awt.Frame;
+import java.security.cert.X509Certificate;
+
+import org.apache.taverna.security.credentialmanager.DistinguishedNameParser;
+import org.apache.taverna.security.credentialmanager.TrustConfirmationProvider;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Stian Soiland-Reyes
+ */
+public class ConfirmTrustedCertificateUI implements TrustConfirmationProvider {
+	private static Logger logger = Logger
+			.getLogger(ConfirmTrustedCertificateUI.class);
+
+	private DistinguishedNameParser dnParser;
+
+	@Override
+	public Boolean shouldTrustCertificate(X509Certificate[] chain) {
+		boolean trustConfirm = false;
+		logger.info("Asking the user if they want to trust a certificate.");
+		// Ask user if they want to trust this service
+		ConfirmTrustedCertificateDialog confirmCertTrustDialog = new ConfirmTrustedCertificateDialog(
+				(Frame) null, "Untrusted HTTPS connection", true,
+				(X509Certificate) chain[0], dnParser);
+		confirmCertTrustDialog.setLocationRelativeTo(null);
+		confirmCertTrustDialog.setVisible(true);
+		trustConfirm = confirmCertTrustDialog.shouldTrust();
+//		trustConfirm.setShouldSave(confirmCertTrustDialog.shouldSave());
+		if (!confirmCertTrustDialog.shouldTrust())
+			showMessageDialog(
+					null,
+					"As you refused to trust this host, you will not be able to use its services from a workflow.",
+					"Untrusted HTTPS connection", INFORMATION_MESSAGE);
+
+		return trustConfirm;
+	}
+
+	/**
+	 * @param dnParser
+	 *            the dnParser to set
+	 */
+	public void setDistinguishedNameParser(DistinguishedNameParser dnParser) {
+		this.dnParser = dnParser;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/CredentialManagerUI.java
----------------------------------------------------------------------
diff --git a/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/CredentialManagerUI.java b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/CredentialManagerUI.java
new file mode 100644
index 0000000..7547918
--- /dev/null
+++ b/taverna-credential-manager-ui/src/main/java/org/apache/taverna/workbench/ui/credentialmanager/CredentialManagerUI.java
@@ -0,0 +1,1511 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.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 org.apache.taverna.workbench.ui.credentialmanager.CMStrings.ALERT_TITLE;
+import static org.apache.taverna.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();
+	}
+}