The state as of 28 October 2009, before wsdl security was added.

git-svn-id: https://taverna.googlecode.com/svn/taverna/ui/net.sf.taverna.t2.ui-components/tags/credential-manager-ui-pre-security-2009-10-28@8707 bf327186-88b3-11dd-a302-d386e5130c1c
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e789797
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>net.sf.taverna.t2</groupId>
+		<artifactId>ui-components</artifactId>
+		<version>0.9</version>
+	</parent>
+	<groupId>net.sf.taverna.t2.ui-components</groupId>
+	<artifactId>credential-manager-ui</artifactId>
+	<version>0.10-SNAPSHOT</version>
+	<name>Credential Manager UI</name>
+	<description>
+		Integrates the Credential Manager into the Workbench
+	</description>
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>menu-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.security</groupId>
+			<artifactId>credential-manager</artifactId>
+			<version>0.6.2</version>
+		</dependency>
+	</dependencies>
+	<repositories>
+		<repository>
+			<releases />
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<id>mygrid-repository</id>
+			<name>myGrid Repository</name>
+			<url>http://www.mygrid.org.uk/maven/repository</url>
+		</repository>
+	</repositories>
+</project>
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CredentialManagerUI.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CredentialManagerUI.java
new file mode 100644
index 0000000..78ccd8b
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CredentialManagerUI.java
@@ -0,0 +1,1585 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+//import java.awt.Component;
+//import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Toolkit;
+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.IOException;
+import java.io.InputStreamReader;
+
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CMX509Util;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.SetMasterPasswordDialog;
+
+import net.sf.taverna.t2.workbench.ui.credentialmanager.CredentialManagerUI;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.CryptoFileFilter;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.EditKeyPairEntryDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.GetPasswordDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.KeyPairsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.NewEditPasswordEntryDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.NewKeyPairEntryDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.NewTrustCertsDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.PasswordsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TableCellRenderer;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TableHeaderRenderer;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TrustedCertsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.ViewCertDetailsDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.ViewUsernamePasswordEntryDialog;
+
+import org.apache.log4j.Logger;
+import org.bouncycastle.openssl.PEMReader;
+import org.bouncycastle.openssl.PEMWriter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.WindowConstants;
+import javax.swing.border.EmptyBorder;
+import javax.swing.table.TableColumn;
+
+/**
+ * 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).
+ * 
+ * @author Alex Nenadic
+ */
+
+@SuppressWarnings("serial")
+public class CredentialManagerUI extends JFrame {
+
+	// Credential Manager UI singleton
+	private static CredentialManagerUI INSTANCE;
+	
+	// Logger 
+	private static Logger logger = Logger.getLogger(CredentialManagerUI.class);
+
+	// Default tabbed pane width - dictates width of this frame 
+	private static final int DEFAULT_FRAME_WIDTH = 600;
+
+	// Default tabbed pane height - dictates height of this frame 
+	private static final int DEFAULT_FRAME_HEIGHT = 400;
+
+	// Credential Manager icon (when frame minimised) 
+	private static final Image credManagerIconImage = Toolkit.getDefaultToolkit()
+			.createImage(CredentialManagerUI.class.getResource("/images/cred_manager_transparent.png"));
+
+	// Credential Manager - manages all operations on the Keystore and Truststore
+	public static CredentialManager credManager;
+	
+	// Keystore tab and table controls
+	
+	// Tabbed pane to hold keystore entries tables 
+	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 = "Key Pairs";
+	
+	// Tab 3: holds key pairs (user certificates) table 
+	private JPanel proxiesTab = new JPanel(new BorderLayout(10, 10));
+
+	// Tab 3: name 
+	public static final String PROXIES = "Proxies";
+
+	// Tab 4: holds trusted certificates table 
+	private JPanel trustedCertificatesTab = new JPanel(new BorderLayout(10, 10));
+
+	// Tab 4: name 
+	public static final String TRUSTED_CERTIFICATES = "Trusted Certificates";
+	
+	// Tables
+
+	// Password entries' table 
+	private JTable passwordsTable;
+
+	// Key Pair entries' table 
+	private JTable keyPairsTable;
+	
+	// Proxy entries' table
+	private JTable proxiesTable;
+
+	// Trusted Certificate entries' table 
+	private JTable trustedCertsTable;
+
+	// Value to place in the Type column for a password entry
+	public static final String PASSWORD_ENTRY_TYPE = "Password";
+
+	// Value to place in the Type column for a key pair entry 
+	public static final String KEY_PAIR_ENTRY_TYPE = "Key Pair";
+	
+	// Value to place in the Type column for a proxy entry 
+	public static final String PROXY_ENTRY_TYPE = "Proxy";
+
+	// Value to place in the Type column for a trusted certificate entry 
+	public static final String TRUST_CERT_ENTRY_TYPE = "Trusted Certificate";
+	
+	
+	/**
+	 * Returns a CredentialManagerUI singleton.
+	 */
+	public static CredentialManagerUI getInstance(){
+		synchronized (CredentialManagerUI.class) {
+			if (INSTANCE == null)
+				try {
+					INSTANCE = new CredentialManagerUI();
+				} catch (CMException cme) {
+					// Failed to instantiate Credential Manager - warn the user and exit
+					String exMessage = "Failed to instantiate Credential Manager. " + cme.getMessage();
+					logger.error(exMessage);
+					JOptionPane.showMessageDialog(new JFrame(), exMessage,
+							"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+				}
+		}
+		return INSTANCE;
+	}
+
+	/**
+	 * 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.
+	 */
+	private CredentialManagerUI() throws CMException
+	{
+
+		// Instantiate Credential Manager that will perform all 
+		// operations on the Keystore and Truststore
+		credManager = CredentialManager.getInstance();
+		
+        // 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));
+		
+		// Button for changing Credential Manager's master password
+		JButton changeMasterPasswordButton = new JButton("Change master password");
+		changeMasterPasswordButton.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				changeMasterPassword();
+			}});
+		JPanel changeMasterPasswordPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+		changeMasterPasswordPanel.add(changeMasterPasswordButton);
+		
+		// Add change master password to the main application frame
+		getContentPane().add(changeMasterPasswordPanel, BorderLayout.NORTH);
+		// Add tabbed pane to the main application frame
+		getContentPane().add(keyStoreTabbedPane, BorderLayout.CENTER);
+
+		// Handle application close
+		addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent evt) {
+				closeFrame();
+			}
+		});
+		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+
+		pack();
+
+		// Centre the frame in the centre of the desktop
+		setLocationRelativeTo(null);
+
+		// Set the frame's icon
+		setIconImage(credManagerIconImage);
+
+		// Set the frame's title
+		setTitle("Credential Manager");
+
+		//setModal(true);
+		//setVisible(true);
+	}
+	
+	protected void changeMasterPassword() {
+
+		SetMasterPasswordDialog changePasswordDialog = new SetMasterPasswordDialog(this, "Change master password", true , "Change master password for Credential Manager");
+		changePasswordDialog.setLocationRelativeTo(null);
+		changePasswordDialog.setVisible(true);
+		String password = changePasswordDialog.getPassword();
+		if (password == null){ // user cancelled
+			return; // do nothing
+		}
+		else{
+			try {
+				credManager.changeMasterPassword(password);
+				JOptionPane.showMessageDialog(new JFrame(), "Master password changed sucessfully",
+						"Credential Manager Error", JOptionPane.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);
+				JOptionPane.showMessageDialog(new JFrame(), exMessage,
+						"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			}
+		}
+	}
+
+	/**
+	 * Initialise the tab on the tabbed pane and its tabular content.
+	 */
+	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();
+			// 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);
+
+			// Buttons
+			JButton newPasswordButton = new JButton("New");
+			newPasswordButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					newPassword();
+				}});
+			JButton viewPasswordButton = new JButton("Details");
+			viewPasswordButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					viewPassword();
+				}});
+			JButton editPasswordButton = new JButton("Edit");
+			editPasswordButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					editPassword();
+				}});
+			JButton deletePasswordButton = new JButton("Delete");
+			deletePasswordButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					deletePassword();
+				}});
+			
+			// 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, BorderLayout.PAGE_END);
+
+		} 
+		else if (tableType.equals(KEYPAIRS)) { // Key Pairs tab
+			// The Key Pairs table's data model
+			KeyPairsTableModel keyPairsTableModel = new KeyPairsTableModel();
+			// The table itself
+			table = new JTable(keyPairsTableModel);
+
+			// Set the alias and service URLs 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 serviceURLsColumn = table.getColumnModel().getColumn(5);
+			table.getColumnModel().removeColumn(serviceURLsColumn);
+
+			// Buttons
+			JButton viewKeyPairButton = new JButton("Details");
+			viewKeyPairButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					viewCertificate();
+				}});
+			JButton editServiceURLKeyPairButton = new JButton("Edit");
+			editServiceURLKeyPairButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					editKeyPair();
+				}});
+			JButton importKeyPairButton = new JButton("Import");
+			importKeyPairButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					newKeyPair();
+				}});
+			JButton exportKeyPairButton = new JButton("Export");
+			exportKeyPairButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					exportKeyPair();
+				}});
+			JButton deleteKeyPairButton = new JButton("Delete");
+			deleteKeyPairButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					deleteKeyPair();
+				}});
+
+			// Panel to hold the buttons
+			JPanel bp = new JPanel();
+			bp.add(viewKeyPairButton);
+			bp.add(editServiceURLKeyPairButton);
+			bp.add(importKeyPairButton);
+			bp.add(exportKeyPairButton);
+			bp.add(deleteKeyPairButton);
+
+			// Add button panel to the tab
+			tab.add(bp, BorderLayout.PAGE_END);
+
+		} 
+		else if (tableType.equals(PROXIES)) { // Proxies tab
+			// The Proxies table's data model
+			ProxiesTableModel proxiesTableModel = new ProxiesTableModel();
+			
+			// The table itself
+			table = new JTable(proxiesTableModel);
+
+			// Set alias column of the Proxies table to be
+			// invisible by removing it from the column model (it will still present
+			// in the table model)
+			TableColumn aliasColumn = table.getColumnModel().getColumn(5); 
+			table.getColumnModel().removeColumn(aliasColumn);
+
+			// Buttons
+			JButton viewProxyButton = new JButton("Details");
+			viewProxyButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					viewProxyCertificate();
+				}});
+			JButton deleteProxyButton = new JButton("Delete");
+			deleteProxyButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					deleteProxy();
+				}});
+			
+
+			// Panel to hold the buttons
+			JPanel bp = new JPanel();
+			bp.add(viewProxyButton);
+			bp.add(deleteProxyButton);
+			
+			// Add button panel to the tab
+			tab.add(bp, BorderLayout.PAGE_END);
+
+		} 
+		else if (tableType.equals(TRUSTED_CERTIFICATES)) { // Trusted Certificates tab
+			// The Trusted Certificate table's data model
+			TrustedCertsTableModel trustedCertificatesTableModel = new TrustedCertsTableModel();
+			// The table itself
+			table = new JTable(trustedCertificatesTableModel);
+
+			// Set the alias column of the Trusted Certs table to be invisible
+			// by removing it from the column model (it is still present in the
+			// table model)
+			TableColumn aliasColumn = table.getColumnModel().getColumn(5);
+			table.getColumnModel().removeColumn(aliasColumn);
+
+			// Buttons
+			JButton viewTrustedCertificateButton = new JButton("Details");
+			viewTrustedCertificateButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					viewCertificate();
+				}});
+			JButton importTrustedCertificateButton = new JButton("Import");
+			importTrustedCertificateButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					importTrustedCertificate();
+				}});
+			JButton exportTrustedCertificateButton = new JButton("Export");
+			exportTrustedCertificateButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					exportTrustedCertificate();
+				}});
+			JButton deleteTrustedCertificateButton = new JButton("Delete");
+			deleteTrustedCertificateButton.addActionListener(new ActionListener(){
+				public void actionPerformed(ActionEvent e) {
+					deleteTrustedCertificate();
+				}});
+
+			// 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, BorderLayout.PAGE_END);
+		}
+
+		table.setShowGrid(false);
+		table.setRowMargin(0);
+		table.getColumnModel().setColumnMargin(0);
+		table.getTableHeader().setReorderingAllowed(false);
+		table.setAutoResizeMode(JTable.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 URL column of Passwords and Key Pairs tables, and
+		// Certificate Name column of the Trusted Certificates table)
+		TableColumn secondCol = table.getColumnModel().getColumn(1);
+		secondCol.setMinWidth(20);
+		secondCol.setMaxWidth(10000);
+		secondCol.setPreferredWidth(300);
+
+		// Don't care about the size of other columns
+
+		// Put the table into a scroll pane
+		JScrollPane jspTableScrollPane = new JScrollPane(table,
+				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+		jspTableScrollPane.getViewport().setBackground(table.getBackground());
+
+		// Put the scroll pane on the tab panel
+		tab.add(jspTableScrollPane, BorderLayout.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() {
+			public void mouseClicked(MouseEvent evt) {
+				tableDoubleClick(evt);
+			}
+		});
+
+		// Add the tab to the tabbed pane
+		keyStoreTabbedPane.addTab(tableType, tab);
+
+		return table;
+	}
+	
+	/**
+	 * Display the username/password pair entry from the Keystore.
+	 */
+	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 URL, username and password
+		String serviceURL = (String) passwordsTable.getValueAt(iRow, 1); // current entry's service URL
+
+		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 URL, username and password of the entry
+		ViewUsernamePasswordEntryDialog viewServicePassDialog = new ViewUsernamePasswordEntryDialog(
+				this, serviceURL, username, password);
+
+		viewServicePassDialog.setLocationRelativeTo(this);
+		viewServicePassDialog.setVisible(true);
+	}
+	
+	/**
+	 * Insert a new username/password pair for a service URL in the Keystore.
+	 */
+	private void newPassword() {
+		
+		String serviceURL = null; // service URL
+		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
+			// URL, username and password)
+			NewEditPasswordEntryDialog newPasswordDialog = new NewEditPasswordEntryDialog(
+					this, "New username and password for a service", true, serviceURL, username,
+					password);
+			newPasswordDialog.setLocationRelativeTo(this);
+			newPasswordDialog.setVisible(true);
+
+			serviceURL = newPasswordDialog.getServiceURL(); // get service URL
+			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 URL
+			// 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' URLs is done in the
+			// NewEditPasswordEntry dialog.
+			
+			// Get list of service URLs for all the password entries in the Keystore
+			ArrayList<String> serviceURLs = null;
+			try{
+				serviceURLs = credManager.getServiceURLsforUsernameAndPasswords(); 
+			}
+			catch(CMException  cme){
+				String exMessage = "Failed to get service URLs for all username and password pairs to check if the entered service URL already exists";
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error",
+						JOptionPane.ERROR_MESSAGE);
+				return;
+			}
+			if (serviceURLs.contains(serviceURL)) { // if such a URL already exists 
+				// Ask if the user wants to overwrite it
+				int iSelected = JOptionPane.showConfirmDialog(this,
+						"The Keystore already contains a password entry with the same service URL.\n"
+								+ "Do you want to overwrite it?",
+						"Credential Manager Alert",
+						JOptionPane.YES_NO_OPTION);
+
+				// Add the new password entry in the Keystore 
+				if (iSelected == JOptionPane.YES_OPTION) {
+					try{
+						credManager.saveUsernameAndPasswordForService(username, password, serviceURL);
+						break;
+					}
+					catch (CMException cme){
+						String exMessage = "Failed to insert a new username and password pair in the Keystore";
+						JOptionPane.showMessageDialog(this, exMessage,
+								"Credential Manager Error",
+								JOptionPane.ERROR_MESSAGE);
+					}
+				}
+			// Otherwise show the same window with the entered service
+			// URL, username and password values
+			} 
+			else {
+				// Add the new password entry in the Keystore
+				try{
+					credManager.saveUsernameAndPasswordForService(username, password, serviceURL);
+					break;
+				}
+				catch (CMException cme){
+					String exMessage = "Failed to insert a new username and password pair in the Keystore";
+					JOptionPane.showMessageDialog(this, exMessage,
+							"Credential Manager Error",
+							JOptionPane.ERROR_MESSAGE);
+				}
+			}
+		} 
+	}
+	
+
+	/**
+	 * Edit a username and password entry or their related service URL in 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 URL, username and password
+		String serviceURL = (String) passwordsTable.getValueAt(iRow, 1); // current entry's service URL
+
+		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 URL, username or password of a password entry
+			NewEditPasswordEntryDialog editPasswordDialog = new NewEditPasswordEntryDialog(
+					this, "Edit username and password for a service", true, serviceURL, username,
+					password);
+
+			editPasswordDialog.setLocationRelativeTo(this);
+			editPasswordDialog.setVisible(true);
+
+			// New values
+			String nServiceURL = editPasswordDialog.getServiceURL(); // get new service URL
+			String nUsername = editPasswordDialog.getUsername(); // get new username
+			String nPassword = editPasswordDialog.getPassword(); // get new password
+
+			if (nPassword == null) { // user cancelled - any of the above three fields is null
+				// do nothing
+				return;
+			}
+
+			// Is anything actually modified?
+			boolean isModified = (!serviceURL.equals(nServiceURL)
+					|| !username.equals(nUsername) || !password
+					.equals(nPassword));
+
+			if (isModified) {
+				// Check if a different password entry with the new URL
+				// (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 URLs for all passwords in the Keystore
+				ArrayList<String> serviceURLs = null;
+				try{
+					serviceURLs = credManager.getServiceURLsforUsernameAndPasswords(); 
+				}
+				catch(CMException  cme){
+					String exMessage = "Failed to get service URLs for all username and password pairs to check if the modified entry already exists";
+					JOptionPane.showMessageDialog(this, exMessage,
+							"Credential Manager Error",
+							JOptionPane.ERROR_MESSAGE);
+					return;
+				}
+			
+				// If the modified service URL already exists and is not the currently selected one
+				if ( (!nServiceURL.equals(serviceURL)) && serviceURLs.contains(nServiceURL)) { 
+
+					int iSelected = JOptionPane.showConfirmDialog(this,
+							"The Keystore already contains username and password pair for the entered service URL.\n"
+									+ "Do you want to overwrite it?",
+							"Credential Manager Alert",
+							JOptionPane.YES_NO_OPTION);
+
+					if (iSelected == JOptionPane.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.
+						try{
+							credManager.deleteUsernameAndPasswordForService(serviceURL);
+							credManager.saveUsernameAndPasswordForService(nUsername, nPassword, nServiceURL);
+							break;
+						}
+						catch (CMException cme){
+							String exMessage = "Failed to update the username and password pair in the Keystore";
+							JOptionPane.showMessageDialog(this, exMessage,
+									"Credential Manager Error",
+									JOptionPane.ERROR_MESSAGE);
+						}
+					}
+				// Otherwise show the same window with the entered
+				// service URL, username and password values
+				} 
+				else {
+					try{
+						if ( !nServiceURL.equals(serviceURL)) {
+							credManager.deleteUsernameAndPasswordForService(serviceURL);
+						}
+						credManager.saveUsernameAndPasswordForService(nUsername, nPassword, nServiceURL);
+						break;
+					}
+					catch (CMException cme){
+						String exMessage = "Failed to update the username and password pair in the Keystore";
+						JOptionPane.showMessageDialog(this, exMessage,
+								"Credential Manager Error",
+								JOptionPane.ERROR_MESSAGE);
+					}
+				}
+			}
+			else{ // nothing actually modified by OK pressed
+				break;
+			}
+		}
+	}
+
+	/**
+	 * Delete the selected username and password entries from the Keystore.
+	 */
+	private void deletePassword() {
+
+		// Which entries have been selected?
+		int[] iRows = passwordsTable.getSelectedRows();
+		if (iRows.length == 0) { // no password entry selected
+			return;
+		}
+
+		// Ask user to confirm the deletion
+		int iSelected = JOptionPane
+				.showConfirmDialog(
+						null,
+						"Are you sure you want to delete the selected username and password entries?",
+						"Credential Manager Alert",
+						JOptionPane.YES_NO_OPTION);
+
+		if (iSelected != JOptionPane.YES_OPTION) {
+			return;
+		}
+					
+		for (int i = iRows.length - 1; i >= 0; i--) { // delete from backwards
+			// Get service URL for the current entry 
+			String serviceURL = (String) passwordsTable.getValueAt(iRows[i], 1); // current entry's service URL
+			try {
+				// Delete the password entry from the Keystore
+				credManager.deleteUsernameAndPasswordForService(serviceURL);
+			} 
+			catch (CMException cme) {
+				String exMessage = "Failed to delete the username and password pair from the Keystore";
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error",
+						JOptionPane.ERROR_MESSAGE);
+			} 
+		}		
+	}
+	
+	/**
+	 * Show the contents of a (user or trusted) certificate.
+	 */
+	@SuppressWarnings("unchecked")
+	private void viewCertificate() {
+
+		int iRow = -1;
+		String alias = null;
+		X509Certificate certToView = null;
+		ArrayList<String> serviceURLs = null;
+		String keystoreType = null;
+		
+		// Are we showing user's public key certificate?
+		if (keyPairsTab.isShowing()){
+			keystoreType = CredentialManager.KEYSTORE;
+			iRow = keyPairsTable.getSelectedRow();
+			
+			if (iRow != - 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(iRow, 6); // current entry's Keystore alias
+
+		    	// Get the list of service URLs for the entry
+		        serviceURLs = (ArrayList<String>) keyPairsTable.getModel().getValueAt(iRow, 5);   
+			}
+		}
+		// Are we showing trusted certificate?
+		else if(trustedCertificatesTab.isShowing()){
+			keystoreType = CredentialManager.TRUSTSTORE;
+			iRow = trustedCertsTable.getSelectedRow();
+			
+			if (iRow != - 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(iRow, 5); 
+			}
+		}
+		
+		if (iRow != -1) { // something has been selected
+			try {
+				// Get the entry's certificate
+				certToView = CMX509Util.convertCertificate(credManager
+						.getCertificate(keystoreType, alias));
+
+				// Supply the certificate and list of URLs to the view
+				// certificate dialog. 
+				ViewCertDetailsDialog viewCertDetailsDialog = new ViewCertDetailsDialog(
+						this, "Certificate details", true, certToView,
+						serviceURLs);
+				viewCertDetailsDialog.setLocationRelativeTo(this);
+				viewCertDetailsDialog.setVisible(true);
+			} 
+			catch (CMException cme) {
+				String exMessage = "Failed to get certificate details to display to the user";
+				logger.error(exMessage);
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			} 
+		} 
+	}
+	
+	/**
+	 * Import a key pair from a PKCS #12 keystore file to the Keystore.
+	 */
+	private void newKeyPair() {
+
+		// 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
+
+		if (importFile == null) {
+			return;
+		}
+
+		// The PKCS #12 keystore is not a file
+		if (!importFile.isFile()) {
+			JOptionPane.showMessageDialog(this, "Your selection is not a file",
+					"Credential Manager Alert", JOptionPane.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 dGetPassword = new GetPasswordDialog(this,
+				"Import key pair entry", true,
+				"Enter the password that was used to encrypt the PKCS #12 file");
+		dGetPassword.setLocationRelativeTo(this);
+		dGetPassword.setVisible(true);
+
+		String pkcs12Password = dGetPassword.getPassword();
+
+		if (pkcs12Password == null) { // user cancelled
+			return;
+		} else if (pkcs12Password.length() == 0) { // 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 using BC provider
+			KeyStore pkcs12 = credManager.loadPKCS12Keystore(importFile, pkcs12Password);
+
+			// Display the import key pair dialog supplying all the private keys
+			// stored in the PKCS #12 file
+			// and a field for the user to enter service URL associated with the
+			// selected key pair
+			// Typically there will be only one private key inside, but could be
+			// more
+			NewKeyPairEntryDialog dImportKeyPair = new NewKeyPairEntryDialog(
+					this, "Credential Manager", true, pkcs12);
+			dImportKeyPair.setLocationRelativeTo(this);
+			dImportKeyPair.setVisible(true);
+
+			// Get the private key and certificate chain of the key pair
+			Key privateKey = dImportKeyPair.getPrivateKey();
+			Certificate[] certChain = dImportKeyPair.getCertificateChain();
+
+			// Get the service URLs
+			ArrayList<String> serviceURLs = dImportKeyPair.getServiceURLs();
+
+			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.containsKeyPair(privateKey, certChain)) {
+				int iSelected = JOptionPane
+						.showConfirmDialog(
+								this,
+								"The keystore already contains the key pair entry with the same private key.\nDo you want to overwrite it?",
+								"Credential Manager Alert",
+								JOptionPane.YES_NO_OPTION);
+
+				if (iSelected != JOptionPane.YES_OPTION) {
+					return;
+				}
+			}
+
+			// Place the private key and certificate chain into the Keystore
+			// and save the service URLs list associated with this key pair
+			credManager.saveKeyPair(privateKey, certChain, serviceURLs);
+
+			// Display success message
+			JOptionPane
+					.showMessageDialog(this, "Key pair import successful",
+							"Credential Manager Alert",
+							JOptionPane.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);
+			JOptionPane.showMessageDialog(this, exMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+		}
+	}
+
+	
+	/**
+	 * Edit service URLs for a given key pair entry.
+	 */
+	@SuppressWarnings("unchecked")
+	private void editKeyPair() {
+		// Which key pair entry has been selected?
+		int iRow = keyPairsTable.getSelectedRow();
+		if (iRow == -1) { // no row currently selected
+			return;
+		}
+
+		// Because the alias column is not visible we call the
+		// getValueAt method on the table model rather than at the JTable
+		String alias = (String) keyPairsTable.getModel().getValueAt(iRow, 6); // current entry's Keystore alias
+
+    	// Get the list of URLs for the alias
+		ArrayList<String> serviceURLs = (ArrayList<String>) keyPairsTable.getModel().getValueAt(iRow, 5);   
+  
+		// Let the user edit the list of service urls this key pair is
+		// associated to
+		EditKeyPairEntryDialog dEditKeyPair = new EditKeyPairEntryDialog(this,
+				"Edit key pair's service URLs", true, serviceURLs);
+
+		dEditKeyPair.setLocationRelativeTo(this);
+		dEditKeyPair.setVisible(true);
+
+		ArrayList<String> newServiceURLs = dEditKeyPair.getServiceURLs(); // new service URLs list
+
+		if (newServiceURLs == null) { // user cancelled
+			return;
+		}
+
+		// Is anything actually modified?
+		boolean isModified = (!serviceURLs.equals(newServiceURLs));
+
+		if (isModified) {
+			try {
+				// Add the new list of URLs for the alias
+				credManager.saveServiceURLsForKeyPair(alias, newServiceURLs);
+			} 
+			catch (CMException cme) {
+				String exMessage = "Failed to update service URLs for the key pair entry";
+				logger.error(exMessage);
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			} 
+		} 
+	}
+
+	/**
+	 * 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 iRow = keyPairsTable.getSelectedRow();
+		if (iRow == -1) { // no row currently selected
+			return;
+		}
+
+		// Get the key pair entry's Keystore alias
+		String alias = (String) keyPairsTable.getModel().getValueAt(iRow, 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
+
+		if (exportFile == null) {
+			return;
+		}
+
+		// If file already exist - ask the user if he wants to overwrite it
+		if (exportFile.isFile()) {
+			int iSelected = JOptionPane
+					.showConfirmDialog(
+							this,
+							"The file with the given name already exists.\nDo you want to overwrite it?",
+							"Credential Manager Alert",
+							JOptionPane.YES_NO_OPTION);
+
+			if (iSelected == JOptionPane.NO_OPTION) {
+				return;
+			}
+		}
+
+		// Get the user to enter the password for the PKCS #12 keystore file
+		GetPasswordDialog dGetPassword = new GetPasswordDialog(this,
+				"Credential Manager", true,
+				"Enter the password for protecting the exported key pair");
+		dGetPassword.setLocationRelativeTo(this);
+		dGetPassword.setVisible(true);
+
+		String pkcs12Password = dGetPassword.getPassword();
+
+		if (pkcs12Password == null) { // user cancelled or empty password
+			// Warn the user
+			JOptionPane
+					.showMessageDialog(
+							this,
+							"You must supply a password for protecting the exported key pair.",
+							"Credential Manager Alert",
+							JOptionPane.INFORMATION_MESSAGE);
+			return;
+		}
+
+		// Export the key pair
+		try {
+			credManager.exportKeyPair(alias, exportFile, pkcs12Password);
+			JOptionPane.showMessageDialog(this, "Key pair export successful",
+							"Credential Manager Alert",
+							JOptionPane.INFORMATION_MESSAGE);
+		} 
+		catch (CMException cme) {
+			JOptionPane.showMessageDialog(this, cme.getMessage(),
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+		} 
+	}
+
+	/**
+	 * Delete selected key pair entries from the Keystore.
+	 */
+	private void deleteKeyPair() {
+		
+		// Which entries have been selected?
+		int[] iRows = keyPairsTable.getSelectedRows();
+		if (iRows.length == 0) { // no key pair entry selected
+			return;
+		}
+
+		// Ask user to confirm the deletion
+		int iSelected = JOptionPane
+				.showConfirmDialog(
+						null,
+						"Are you sure you want to delete the selected key pairs?",
+						"Credential Manager Alert",
+						JOptionPane.YES_NO_OPTION);
+
+		if (iSelected != JOptionPane.YES_OPTION) {
+			return;
+		}
+					
+		for (int i = iRows.length - 1; i >= 0; i--) { // delete from backwards
+			// Get the alias for the current entry 
+			String alias = (String) keyPairsTable.getModel().getValueAt(
+					iRows[i], 6);
+			try {
+				// Delete the key pair entry from the Keystore
+				// and URLs associated with this key pair entry
+				credManager.deleteKeyPair(alias);
+			} 
+			catch (CMException cme) {
+				String exMessage = "Failed to delete the key pair(s) from the Keystore";
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error",
+						JOptionPane.ERROR_MESSAGE);
+			} 
+		}
+	}
+	
+	/**
+	 * Show the contents of a proxy certificate.
+	 */
+	private void viewProxyCertificate() {
+
+		int iRow = proxiesTable.getSelectedRow();
+		
+		if (iRow != -1) { // something has been selected
+			String alias = (String) proxiesTable.getModel().getValueAt(iRow, 5);
+			
+			if (alias.startsWith("cagridproxy#")){ // cagrid proxy
+				try {
+					// Get the entry's certificate
+					X509Certificate certToView = CMX509Util.convertCertificate(credManager
+							.getCertificate(CredentialManager.KEYSTORE, alias));
+
+					String authNServiceURL = alias.substring(alias.indexOf('#') + 1, alias.indexOf(' '));
+					String dorianServiceURL = alias.substring(alias.indexOf(' ') +1); 
+					// Supply the certificate and list of URLs to the view
+					// certificate dialog. 
+					ViewCaGridProxyCertDetailsDialog viewCaGridProxyCertDetailsDialog = new ViewCaGridProxyCertDetailsDialog(
+							this, "Certificate details", true, certToView, authNServiceURL, dorianServiceURL);
+					viewCaGridProxyCertDetailsDialog.setLocationRelativeTo(this);
+					viewCaGridProxyCertDetailsDialog.setVisible(true);
+				} 
+				catch (CMException cme) {
+					String exMessage = "Failed to get proxy certificate details to display to the user";
+					logger.error(exMessage);
+					JOptionPane.showMessageDialog(this, exMessage,
+							"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+				} 
+			}
+			//else{} // some other proxy
+		} 
+	}
+	
+	/**
+	 * Delete selected proxy entries from the Keystore.
+	 */
+	private void deleteProxy() {
+		
+		// Which entries have been selected?
+		int[] iRows = proxiesTable.getSelectedRows();
+		if (iRows.length == 0) { // no key pair entry selected
+			return;
+		}
+
+		// Ask user to confirm the deletion
+		int iSelected = JOptionPane
+				.showConfirmDialog(
+						null,
+						"Are you sure you want to delete the selected proxy(ies)?",
+						"Credential Manager Alert",
+						JOptionPane.YES_NO_OPTION);
+
+		if (iSelected != JOptionPane.YES_OPTION) {
+			return;
+		}
+					
+		for (int i = iRows.length - 1; i >= 0; i--) { // delete from backwards
+			// Get the alias for the current entry 
+			String alias = (String) proxiesTable.getModel().getValueAt(
+					iRows[i], 5);
+			try {
+				// Delete the proxy entry from the Keystore
+				credManager.deleteCaGridProxy(alias);
+			} 
+			catch (CMException cme) {
+				String exMessage = "Failed to delete the proxy(ies) from the Keystore";
+				logger.error(exMessage);
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error",
+						JOptionPane.ERROR_MESSAGE);
+			} 
+		}
+	}
+
+	/**
+	 * 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", ".p7c" }, // file extensions filters
+				"Certificate Files (*.pem, *.crt, , *.cer, *.der, *.p7c)", // filter description
+				"Import"); // text for the file chooser's approve button
+
+		if (certFile == null) {
+			return;
+		}
+
+		// Load the certificate(s) from the file
+		ArrayList<X509Certificate> trustCertsList = new ArrayList<X509Certificate>();
+		FileInputStream fis = null;
+
+		try {
+			fis = new FileInputStream(certFile);
+			CertificateFactory cf = CertificateFactory.getInstance("X.509");
+			// The following should be able to load PKCS #7 certificate chain files
+			// as well as ASN.1 DER or PEM-encoded (sequences of) certificates
+			Collection<? extends Certificate> c = cf.generateCertificates(fis);
+			Iterator<? extends Certificate> i = c.iterator();
+			while (i.hasNext()) {
+				trustCertsList.add((X509Certificate) i.next());
+			}
+		} 
+		catch (Exception cex) {
+			// Do nothing
+		} 
+		finally {
+			try {
+				fis.close();
+			} catch (Exception ex) {
+				// ignore
+			}
+		}
+
+		if (trustCertsList.size() == 0) { // Could not load certificates as
+			// any of the above types
+			try {
+				// Try as openssl PEM format - which sligtly differs from the
+				// one supported by JCE
+				fis = new FileInputStream(certFile);
+				CertificateFactory cf = CertificateFactory.getInstance("X.509");
+				PEMReader pr = new PEMReader(new InputStreamReader(fis), null,
+						cf.getProvider().getName());
+				Object cert;
+				while ((cert = pr.readObject()) != null) {
+					if (cert instanceof X509Certificate) {
+						trustCertsList.add((X509Certificate) cert);
+					}
+				}
+			} catch (Exception cex) {
+				// do nothing
+			} finally {
+				try {
+					fis.close();
+				} catch (Exception ex) {
+					// ignore
+				}
+			}
+		}
+
+		if (trustCertsList.size() == 0) { // Failed to load certifcate(s)
+			// using any of the known encodings
+			JOptionPane
+					.showMessageDialog(
+							this,
+							"Failed to load certificate(s) using any of the known encodings -\nfile format not recognised.",
+							"Credential Manager Error",
+							JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+
+		// Show the list of certificates contained in the file for the user to
+		// select the ones to import
+		NewTrustCertsDialog dImportTrustCerts = new NewTrustCertsDialog(this,
+				"Credential Manager", true, trustCertsList);
+
+		dImportTrustCerts.setLocationRelativeTo(this);
+		dImportTrustCerts.setVisible(true);
+		ArrayList<X509Certificate> selectedTrustCerts = dImportTrustCerts
+				.getTrustedCertificates(); // user-selected trusted certs to import
+
+		// If user cancelled or did not select any cert to import
+		if ((selectedTrustCerts) == null || (selectedTrustCerts.size() == 0)) { 
+			return ;
+		}
+
+		try {
+			
+			for (int i = selectedTrustCerts.size() - 1; i >= 0; i--) {
+				// Import the selected trusted certificates
+				credManager.saveTrustedCertificate(selectedTrustCerts.get(i));
+			}
+
+			// Display success message
+			JOptionPane
+					.showMessageDialog(this,
+							"Trusted certificate(s) import successful",
+							"Credential Manager Alert",
+							JOptionPane.INFORMATION_MESSAGE);
+		} 
+		catch (CMException cme) {
+			String exMessage = "Failed to import trusted certificate(s) to the Truststore";
+			logger.error(exMessage);
+			JOptionPane.showMessageDialog(this, exMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+		} 
+	}
+
+	
+	/**
+	 * Lets the user export one (at the moment) or more (in future) trusted
+	 * certificate entries to a PEM-encoded file.
+	 * 
+	 * @return True if the export is successful, false otherwise
+	 */
+	private boolean exportTrustedCertificate() {
+
+		// Which trusted certificate has been selected?
+		int iRow = trustedCertsTable.getSelectedRow();
+		if (iRow == -1) { // no row currently selected
+			return false;
+		}
+
+		// Get the trust certificate entry's Keystore alias
+		String alias = (String) trustedCertsTable.getModel().getValueAt(iRow, 3); 
+		// the alias column is invisible so we get the value from the table model
+
+		// Let the user choose a file to export public and private key pair 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
+
+		if (exportFile == null) {
+			return false;
+		}
+
+		// If file already exist - ask the user if he wants to overwrite it
+		if (exportFile.isFile()) {
+			int iSelected = JOptionPane
+					.showConfirmDialog(
+							this,
+							"The file with the given name already exists.\nDo you want to overwrite it?",
+							"Credential Manager Alert",
+							JOptionPane.YES_NO_OPTION);
+
+			if (iSelected == JOptionPane.NO_OPTION) {
+				return false;
+			}
+		}
+
+		// Export the trusted certificate
+		PEMWriter pw = null;
+		try {
+			// Get the trusted certificate
+			Certificate certToExport = credManager.getCertificate(
+					CredentialManager.TRUSTSTORE, alias);
+			pw = new PEMWriter(new FileWriter(exportFile));
+			pw.writeObject(certToExport);
+
+			JOptionPane
+					.showMessageDialog(this,
+							"Trusted certificate export successful",
+							"Credential Manager Alert",
+							JOptionPane.INFORMATION_MESSAGE);
+
+			return true;
+		} 
+		catch (Exception ex) {
+			String exMessage = "Failed to export the trusted certificate from the Truststore.";
+			logger.error(exMessage);
+			JOptionPane.showMessageDialog(
+							this,
+							exMessage,
+							"Credential Manager Error",
+							JOptionPane.ERROR_MESSAGE);
+			return false;
+		} 
+		finally {
+			if (pw != null) {
+				try {
+					pw.close();
+				} catch (IOException ex) {
+					// ignore
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Delete selected trusted certificate entries from the Truststore.
+	 */
+	private void deleteTrustedCertificate() {
+		
+		// Which entries have been selected?
+		int[] iRows = trustedCertsTable.getSelectedRows();
+		if (iRows.length == 0) { // no trusted cert entry selected
+			return;
+		}
+
+		// Ask user to confirm the deletion
+		int iSelected = JOptionPane
+				.showConfirmDialog(
+						null,
+						"Are you sure you want to delete the selected trusted certificate(s)?",
+						"Credential Manager Alert",
+						JOptionPane.YES_NO_OPTION);
+
+		if (iSelected != JOptionPane.YES_OPTION) {
+			return;
+		}
+					
+		for (int i = iRows.length - 1; i >= 0; i--) { // delete from backwards
+			// Get the alias for the current entry 
+			String alias = (String) trustedCertsTable.getModel().getValueAt(
+					iRows[i], 5);
+			try {
+				// Delete the trusted certificate entry from the Truststore
+				credManager.deleteTrustedCertificate(alias);
+			} 
+			catch (CMException cme) {
+				String exMessage = "Failed to delete the trusted certificate(s) from the Truststore";
+				logger.error(exMessage);
+				JOptionPane.showMessageDialog(this, exMessage,
+						"Credential Manager Error",
+						JOptionPane.ERROR_MESSAGE);
+			} 
+		}
+	}
+	
+	/**
+	 * Handle double click on the Keystore tables. If it has occurred, show the
+	 * details of the entry clicked upon.
+	 */
+	private void tableDoubleClick(MouseEvent evt) {
+		if (evt.getClickCount() > 1) { // is it double click?
+
+			// What row and column were clicked upon (if any)?
+			Point point = new Point(evt.getX(), evt.getY());
+			int iRow = ((JTable) evt.getSource()).rowAtPoint(point);
+			if (iRow == -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 if (((JTable) evt.getSource()).getModel() instanceof ProxiesTableModel) { //Proxies table
+				viewProxyCertificate();
+			}
+			else { // Trusted certificates table
+				viewCertificate();
+			}
+		}
+	}
+	
+	/**
+	 * Let the user select a file to export to or import from a key pair or a
+	 * certificate. The file types are filtered according to their extensions:
+	 * .p12 or .pfx are PKCS #12 keystore files containing private key and its
+	 * public key (+cert chain) .crt are ASN.1 PEM-encoded files containing one
+	 * (or more concatenated) public key certificate(s) .der are ASN.1
+	 * DER-encoded files containing one public key certificate .cer are
+	 * CER-encoded files containing one ore more DER-encoded certificates
+	 */
+	private File selectImportExportFile(String title, String[] filter,
+			String description, String approveButtonText) {
+
+		JFileChooser chooser = new JFileChooser();
+		chooser
+				.addChoosableFileFilter(new CryptoFileFilter(filter,
+						description));
+		chooser.setDialogTitle(title);
+		chooser.setMultiSelectionEnabled(false);
+
+		int rtnValue = chooser.showDialog(this, approveButtonText);
+		if (rtnValue == JFileChooser.APPROVE_OPTION) {
+			File selectedFile = chooser.getSelectedFile();
+			return selectedFile;
+		}
+		return null;
+	}
+	
+	/**
+	 * Exit the UI's frame.
+	 */
+	private void closeFrame() {
+		setVisible(false);
+		dispose();
+	}
+
+	
+//	/**
+//	 * Set cursor to busy and disable application input. This can be reversed by
+//	 * a subsequent call to setCursorFree.
+//	 */
+//	private void setCursorBusy() {
+//		// Block all mouse events using glass pane
+//		Component glassPane = getRootPane().getGlassPane();
+//		glassPane.addMouseListener(new MouseAdapter() {
+//		});
+//		glassPane.setVisible(true);
+//
+//		// Set cursor to busy
+//		glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+//	}
+//
+//	
+//	/**
+//	 * Set cursor to free and enable application input. Called after a call to
+//	 * setCursorBusy.
+//	 */
+//	private void setCursorFree() {
+//		// Accept mouse events
+//		Component glassPane = getRootPane().getGlassPane();
+//		glassPane.setVisible(false);
+//
+//		// Revert cursor to default
+//		glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+//	}
+//			
+//	/**
+//	 * Action helper class.
+//	 */
+//	private abstract class AbstractAction extends javax.swing.AbstractAction {
+//		protected abstract void act();
+//
+//		public void actionPerformed(ActionEvent evt) {
+//			setCursorBusy();
+//			repaint();
+//			new Thread(new Runnable() {
+//				public void run() {
+//					try {
+//						act();
+//					} finally {
+//						setCursorFree();
+//					}
+//				}
+//			}).start();
+//		}
+//	}
+
+}
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CredentialManagerUILauncher.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CredentialManagerUILauncher.java
new file mode 100644
index 0000000..cc7500a
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CredentialManagerUILauncher.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+/**
+ * 
+ * Test launcher for Credential Manager GUI (so it does not have to be
+ * launched from Taverna).
+ * @author Alexandra Nenadic
+ *
+ */
+public class CredentialManagerUILauncher extends JFrame {
+	
+	private static final long serialVersionUID = 2079805060170251148L;
+	
+	private final ImageIcon launchCMIcon = new ImageIcon(CredentialManagerUILauncher.class.getResource(
+	"/images/cred_manager.png"));
+	
+	public CredentialManagerUILauncher(){
+		
+		JPanel jpLaunch = new JPanel();
+		jpLaunch.setPreferredSize(new Dimension (300, 120));
+		
+		JLabel jlLaunch = new JLabel("T2: Launch Credential Manager GUI");
+		
+		JButton jbLaunch = new JButton();
+		jbLaunch.setIcon(launchCMIcon);
+		jbLaunch.setToolTipText("Launches Credential Manager");
+		jbLaunch.addActionListener(new ActionListener(){
+
+			public void actionPerformed(ActionEvent e) {
+				CredentialManagerUI cmGUI = CredentialManagerUI.getInstance();
+				//if (cmGUI.isInitialised()){
+					cmGUI.setVisible(true);
+				//}
+			}
+		});
+		
+		jpLaunch.add(jlLaunch);
+		jpLaunch.add(jbLaunch);
+
+		getContentPane().add(jpLaunch,BorderLayout.CENTER);
+		
+        // Handle application close
+        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+    
+		pack();
+
+        // Centre the frame in the centre of the desktop
+        setLocationRelativeTo(null);
+        
+        // Set the frame's title
+        setTitle("Credential Manager GUI Launcher");
+        
+        setVisible(true);
+		
+	}
+	
+	
+    /**
+     * Runnable to create and show the Credential Manager Launcher's GUI.
+     */
+    private static class CreateAndShowGui
+        implements Runnable
+    {
+
+        /**
+         * Create and show the launcher GUI.
+         */
+        public void run()
+        {
+            new CredentialManagerUILauncher();
+        }
+    }
+    
+    
+    /**
+     * Launcher for the Credential Manager GUI.
+     */
+    public static void main(String[] args)
+    {
+        // Create and show GUI on the event handler thread
+        SwingUtilities.invokeLater(new CreateAndShowGui());
+    }
+
+}
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CryptoFileFilter.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CryptoFileFilter.java
new file mode 100644
index 0000000..4b49868
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/CryptoFileFilter.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * 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 java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * File filter for filtering against various file extensions.
+ * 
+ * @author Alexandra Nenadic
+ */
+public class CryptoFileFilter extends javax.swing.filechooser.FileFilter 
+{
+	/** Description of the filter */
+	private String description;
+	
+	/** Array of file extensions to filter against */
+	private ArrayList<String> exts = new ArrayList<String>();
+	
+    /**
+     * Construct a CryptoFileFilter for a set of related file extensions.
+     *
+     * @param extList Array of file extensions
+     * @param sDescription Short collective description for the file extensions
+     */
+    public CryptoFileFilter(String [] extList, String sDescription)
+    {
+        for (int i = 0; i < extList.length; i++) {
+            addType (extList[i]);
+        }
+        description = sDescription;
+    }
+
+	private void addType(String s) {
+		exts.add(s);
+	}
+
+	/** Return true if the given file is accepted by this filter. */
+	public boolean accept(File f) 
+	{
+		// Little trick: if you don't do this, only directory names
+		// ending in one of the extentions appear in the window.
+		if (f.isDirectory()) 
+	    {
+	    	return true;
+	    } 
+	    else if (f.isFile()) 
+	    {
+	    	Iterator<String> it = exts.iterator();
+	    	while (it.hasNext()) {
+	        if (f.getName().toLowerCase().endsWith((String) it.next()))
+	        	return true;
+	    	}
+	    }
+	    // A file that didn't match.
+	    return false;
+	  }
+
+	  /** Set the printable description of this filter. */
+	  public void setDescription(String s) {
+	    description = s;
+	  }
+
+	  /** Return the printable description of this filter. */
+	  public String getDescription() {
+	    return description;
+	  }
+	}
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/EditKeyPairEntryDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/EditKeyPairEntryDialog.java
new file mode 100644
index 0000000..3f72a34
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/EditKeyPairEntryDialog.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * 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 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 javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.GetServiceURLDialog;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+import java.awt.Dimension;
+
+/**
+ * Dialog used for editing service urls associated with a key pair entry.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class EditKeyPairEntryDialog
+    extends JDialog
+{
+
+	// Service URLs entry list 
+    private JList jltServiceURLs;
+
+    // Stores service URLs entered 
+    private ArrayList<String> serviceURLs;
+
+	private Logger logger = Logger.getLogger(EditKeyPairEntryDialog.class);
+
+    /**
+     * Creates new EditKeyPairEntryDialog dialog where the parent is a frame.
+     */
+    public EditKeyPairEntryDialog(JFrame parent, String title, boolean modal, ArrayList<String> serviceURLs)
+    {
+        super(parent, title, modal);
+        this.serviceURLs = serviceURLs;
+        initComponents();
+    }
+
+    /**
+     * Creates new EditKeyPairEntryDialog dialog where the parent is a dialog.
+     */
+    public EditKeyPairEntryDialog(JDialog parent, String title, boolean modal, ArrayList<String> serviceURLs)
+    {
+        super(parent, title, modal);
+        this.serviceURLs = serviceURLs;
+        initComponents();
+    }
+
+    /**
+     * Get the service URLs set in the dialog.
+     */
+    public ArrayList<String> getServiceURLs()
+    {
+          return serviceURLs;
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+        
+        // Label
+        JLabel jlServiceURLs = new JLabel("Service URLs this key pair will be used for:");             
+        jlServiceURLs.setFont(new Font(null, Font.PLAIN, 11));
+        jlServiceURLs.setBorder(new EmptyBorder(5,5,5,5));   
+        
+        // Service URLs list
+        DefaultListModel jltModel = new DefaultListModel();
+        jltServiceURLs = new JList(jltModel); 
+        // Populate the list with current values
+        for (String url : serviceURLs){
+        	jltModel.addElement(url);
+        }
+        jltServiceURLs.setVisibleRowCount(5); //don't show more than 5, otherwise the window is too big
+        
+        // 'Add' service URL button
+        JButton addButton = new JButton("+");
+        addButton.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent evt)
+            {
+            	addServiceURLPressed();
+            }       	
+        });
+        addButton.setEnabled(true);
+        // 'Remove' service URL button
+        final JButton removeButton = new JButton("-");
+        removeButton.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent evt)
+            {
+            	// get selected indices
+            	int[] selected = jltServiceURLs.getSelectedIndices();
+            	for (int i = selected.length -1; i>=0 ; i--){
+            		 ((DefaultListModel) jltServiceURLs.getModel()).remove(selected[i]);
+            	}
+            }       	
+        });
+        removeButton.setEnabled(false);
+        jltServiceURLs.addListSelectionListener(new ListSelectionListener()
+        {
+            public void valueChanged(ListSelectionEvent evt)
+            {
+                if (jltServiceURLs.getSelectedIndex() == -1) {
+                	removeButton.setEnabled(false);
+                }
+                else {
+                	removeButton.setEnabled(true);
+                }
+            }
+        });
+        
+        // Scroll pane for service URLs list
+        JScrollPane jspServiceURLs = new JScrollPane(jltServiceURLs,
+                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        jspServiceURLs.getViewport().setBackground(jltServiceURLs.getBackground());
+        
+        // Panel for Add and Remove buttons
+        JPanel jpServiceURLsButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpServiceURLsButtons.add(addButton);
+        jpServiceURLsButtons.add(removeButton);
+        
+        // Panel to hold the list scroll pane and Add/Remove buttons panel
+        JPanel jpServiceURLs = new JPanel(new BorderLayout());
+        jpServiceURLs.add(jlServiceURLs, BorderLayout.NORTH);
+        jpServiceURLs.add(jspServiceURLs, BorderLayout.CENTER);
+        jpServiceURLs.add(jpServiceURLsButtons, BorderLayout.SOUTH);
+        jpServiceURLs.setBorder(new CompoundBorder(
+                new EmptyBorder(15, 15, 15, 15), new EtchedBorder()));
+        jpServiceURLs.setPreferredSize(new Dimension(300, 250));
+        
+        // OK button
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        // Cancel buton
+        JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+        // Panel for OK and Cancel buttons
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+        jpButtons.add(jbCancel);
+
+        getContentPane().add(jpServiceURLs, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * OK button pressed or otherwise activated.
+     */
+    private void okPressed()
+    {
+    	// Get Service URLs
+    	serviceURLs = new ArrayList<String>();
+    	Enumeration<?> URLs = (((DefaultListModel) jltServiceURLs.getModel()).elements());
+    	 for( ; URLs.hasMoreElements(); ){
+    		 serviceURLs.add((String) URLs.nextElement());
+    	 }
+        closeDialog();
+    }
+    
+    
+    /**
+     * Add Service URL button pressed.
+     */
+    public void addServiceURLPressed(){
+    	
+    	// Display the dialog for entering service URL
+    	GetServiceURLDialog dGetServiceURL = new GetServiceURLDialog(this, true);
+        
+    	dGetServiceURL.setLocationRelativeTo(this);
+    	dGetServiceURL.setVisible(true);
+    	
+        String sURL = dGetServiceURL.getServiceURL();
+        
+        if (sURL == null){ // user cancelled
+        	return;
+        }
+        
+        if (sURL.length() == 0){ // user entered empty URL
+       		// Warn the user
+        	JOptionPane.showMessageDialog(
+            		this, 
+            		"The URL cannot be empty",
+        			"Credential Manager Alert",
+        			JOptionPane.INFORMATION_MESSAGE);
+        	return;
+        }
+        
+    	// Check if the entered URL already exist in the URL list for this key entry
+    	if (((DefaultListModel) jltServiceURLs.getModel()).contains(sURL)){
+
+    		// Warn the user
+        	JOptionPane.showMessageDialog(
+            		this, 
+            		"The entered URL already exists in the list of URLs for this key pair entry",
+        			"Credential Manager Alert",
+        			JOptionPane.INFORMATION_MESSAGE);
+        	return;
+    	}
+		
+		// Check if the entered URL is already associated with another key pair entry in the Keystore
+    	// This check should exclude the current entry from the map of URLs being searched
+    	// really (we've already checked for it in the jltServiceURLs) - but does not really matter anyway
+    	
+    	CredentialManager credManager = null;
+    	try {
+			credManager = CredentialManager.getInstance();
+		} catch (CMException cme) {
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String exMessage = "Failed to instantiate Credential Manager";
+			logger .error(exMessage, cme);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), exMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+		}  
+		
+    	HashMap<String, ArrayList<String>> urlMap = credManager.getServiceURLsforKeyPairs();
+       	if (urlMap != null){ // should not be null really (although can be empty). Check anyway.
+        	Set<String> aliases = urlMap.keySet();
+        	for (Iterator<String> i = aliases.iterator(); i.hasNext(); ){
+        		String alias = (String) i.next();
+        		// Check if url list for this alias contains the newly entered url
+        		ArrayList<String> urls = (ArrayList<String>) urlMap.get(alias);
+        		if (urls.contains(sURL)){
+            		// Warn the user and exit
+                	JOptionPane.showMessageDialog(
+                    		this, 
+                    		"The entered URL is already associated with another key pair entry",
+                			"Credential Manager Alert",
+                			JOptionPane.INFORMATION_MESSAGE);
+                	return;
+        		}    		
+        	 }
+       	}
+    	
+		// Check if the entered URL is already associated with a password entry in the Keystore
+//    	ArrayList<String> urlList = (ArrayList<String>) ((CredentialManagerUI) this.getParent()).getURLsForPasswords();
+//		// Check if this url list contains the newly entered url
+//		if (urlList.contains(sURL)){
+//    		// Warn the user and exit
+//        	JOptionPane.showMessageDialog(
+//            		this, 
+//            		"The entered URL is already associated with another password entry",
+//        			"Credential Manager Alert",
+//        			JOptionPane.INFORMATION_MESSAGE);
+//        	return;
+//		}    	
+    	
+    	// Otherwise - the entered URL is not already associated with a different entry in the Keystore, 
+		// so add this URL to the list of URLs for this key pair entry
+        ((DefaultListModel) jltServiceURLs.getModel()).addElement(sURL);
+        int index = ((DefaultListModel) jltServiceURLs.getModel()).getSize() - 1;
+        // Element is appended to the list - get its index
+        jltServiceURLs.setSelectedIndex(index);
+        // Insure the newly added URL is visible
+        jltServiceURLs.ensureIndexIsVisible(index);
+
+    }
+    
+
+    /**
+     * Cancel button pressed or otherwise activated.
+     */
+    private void cancelPressed()
+    {
+       	// Set serviceURLs to null as it might have changed in the meantime
+    	// if user entered some value than pressed cancel later on
+    	serviceURLs = null;       
+    	closeDialog();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetNewPasswordDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetNewPasswordDialog.java
new file mode 100644
index 0000000..7b8f63c
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetNewPasswordDialog.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * 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 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.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * Dialog used for entering and confirming a password.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class GetNewPasswordDialog extends JDialog {
+
+	// Instructions for user explaining the purpose of the password 
+	private String instructions = null;
+	
+    // First password entry password field 
+    private JPasswordField jpfFirst;
+
+    // Password confirmation entry password field 
+    private JPasswordField jpfConfirm;
+
+    // Stores new password entered 
+    private String password = null;
+
+    /**
+     * Creates new GetNewPasswordDialog where the parent is a frame.
+     */
+    public GetNewPasswordDialog(JFrame parent, String title, boolean modal, String instr)
+    {
+        super(parent, title, modal);
+        instructions = instr;
+        initComponents();
+    }
+
+    /**
+     * Creates new GetNewPasswordDialog where the parent is a dialog.
+     */
+    public GetNewPasswordDialog(JDialog parent, String title, boolean modal, String instr)
+    {
+        super(parent, title, modal);
+        instructions = instr;
+        initComponents();
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+
+        JLabel jlFirst = new JLabel("Enter New Password:");
+        JLabel jlConfirm = new JLabel("Confirm New Password:");
+        jpfFirst = new JPasswordField(15);
+        jpfConfirm = new JPasswordField(15);
+
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+        JLabel jlInstructions;
+        if (instructions != null){
+        	jlInstructions = new JLabel (instructions);
+        	jlInstructions.setFont(new Font(null, Font.PLAIN, 11));
+        	jlInstructions.setBorder(new EmptyBorder(5,5,5,5));
+        	getContentPane().add(jlInstructions, BorderLayout.NORTH);
+        }
+        
+        JPanel jpPassword = new JPanel(new GridLayout(2, 2, 5, 5));
+        jpPassword.add(jlFirst);
+        jpPassword.add(jpfFirst);
+        jpPassword.add(jlConfirm);
+        jpPassword.add(jpfConfirm);
+        jpPassword.setBorder(new EmptyBorder(5, 5, 5, 5));
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbCancel);
+        jpButtons.add(jbOK);
+
+        getContentPane().add(jpPassword, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+
+    /**
+     * Get the password set in the dialog or null if none was set.
+     */
+    public String getPassword()
+    {
+    	return password;
+    }
+    
+    /**
+     * Check the following:
+     * <ul>
+     *     <li>that the user has supplied and confirmed a password
+     *     <li>that the password's match
+     *     <li>that the passwords are not empty
+     * </ul>
+     * and store the new password.
+     *
+     * @return true, if the user's dialog entry matches the above criteria,
+     *         false otherwise
+     */
+    private boolean checkPassword()
+    {
+        String sFirstPassword = new String(jpfFirst.getPassword());
+        String sConfirmPassword = new String(jpfConfirm.getPassword());
+
+        if ((sFirstPassword.equals(sConfirmPassword)) && (sFirstPassword.length()!= 0)) { //passwords match and not empty
+            password = sFirstPassword;
+            return true;
+        }
+        else if ((sFirstPassword.equals(sConfirmPassword)) && (sFirstPassword.length() == 0)) { //passwords match but are empty
+            JOptionPane.showMessageDialog(this,
+                    "The password cannot be empty", 
+                    "Credential Manager Warning",
+                    JOptionPane.WARNING_MESSAGE);
+
+                return false;
+        }
+        else{ // passwords do not match
+
+       	JOptionPane.showMessageDialog(this,
+       			"The passwords do not match", 
+       			"Credential Manager Warning",
+       			JOptionPane.WARNING_MESSAGE);
+
+       	return false;
+        }
+    }
+
+    /**
+     * OK button pressed or otherwise activated.
+     */
+    private void okPressed()
+    {
+        if (checkPassword()) {
+            closeDialog();
+        }
+    }
+
+    /**
+     * Cancel button pressed or otherwise activated.
+     */
+    private void cancelPressed()
+    {
+    	// Set the password to null as it might have changed in the meantime 
+    	// if user entered something previously
+    	password = null;
+        closeDialog();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetPasswordDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetPasswordDialog.java
new file mode 100644
index 0000000..8f2588d
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetPasswordDialog.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * 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 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 javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * Dialog used for entering a password.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class GetPasswordDialog extends JDialog {
+
+	// Instructions for user explaining the purpose of the password 
+	private String instructions = null;
+	
+    // Password entry password field 
+    private JPasswordField jpfPassword;
+
+    // Stores the password entered 
+    private String password = null;
+
+    /**
+     * Creates new GetPasswordDialog dialog where the parent is a frame.
+     */
+    public GetPasswordDialog(JFrame parent, String title, boolean modal, String instr)
+    {
+        super(parent, title, modal);
+        instructions = instr;
+        initComponents();
+    }
+
+    /**
+     * Creates new GetPasswordDialog dialog where the parent is a dialog.
+     */
+    public GetPasswordDialog(JDialog parent, String title, boolean modal, String instr)
+    {
+        super(parent, title, modal);
+        instructions = instr;
+        initComponents();
+    }
+
+    /**
+     * Get the password set in the dialog.
+     *
+     * @return The password or null if none was set
+     */
+    public String getPassword()
+    {
+    	return password;
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+               	
+        JLabel jlPassword = new JLabel("Password");
+        jpfPassword = new JPasswordField(15);
+
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+             
+        JLabel jlInstructions; // Instructions
+        if (instructions != null){
+        	jlInstructions = new JLabel (instructions);
+        	jlInstructions.setFont(new Font(null, Font.PLAIN, 11));
+        	jlInstructions.setBorder(new EmptyBorder(5,5,5,5));
+        	getContentPane().add(jlInstructions, BorderLayout.NORTH);
+        }
+        
+        JPanel jpPassword = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpPassword.add(jlPassword);
+        jpPassword.add(jpfPassword);
+        jpPassword.setBorder(new EmptyBorder(5, 5, 5, 5));
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+        jpButtons.add(jbCancel);
+
+        getContentPane().add(jpPassword, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * Check that the password entered is not empty and 
+     * store the entered password.
+     */
+    private boolean checkPassword()
+    {
+        password = new String(jpfPassword.getPassword());
+
+        
+        if (password.length() == 0) { //password is empty          
+            JOptionPane.showMessageDialog(this,
+                    "The password cannot be empty", 
+                    "Credential Manager Warning",
+                    JOptionPane.WARNING_MESSAGE);
+            return false;
+        }
+        else { //password is not empty
+        	return true;
+        }
+
+    }
+    
+    /**
+     * OK button pressed or otherwise activated.
+     */
+    private void okPressed()
+    {
+        if (checkPassword()) {
+            closeDialog();
+        }
+    }
+
+    /**
+     * Cancel button pressed or otherwise activated.
+     */
+    private void cancelPressed()
+    {
+    	password = null;
+        closeDialog();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetServiceURLDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetServiceURLDialog.java
new file mode 100644
index 0000000..85c1c14
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/GetServiceURLDialog.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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 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 javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * Dialog used for entering a service URL.
+ * 
+ * @author Alexandra Nenadic
+ */
+
+public class GetServiceURLDialog extends JDialog
+{
+	
+	private static final long serialVersionUID = -2023348569964325951L;
+
+	// Password entry password field /
+    private JTextField jtfServiceURL;
+
+    // Stores the service URL entered /
+    private String serviceURL = null;
+
+    /**
+     * Creates new GetServiceURLDialog dialog where the parent is a frame.
+     */
+    public GetServiceURLDialog(JFrame parent, boolean modal)
+    {
+        super(parent, "Enter service URL", modal);
+        initComponents();
+    }
+
+    /**
+     * Creates new GetServiceURLDialog dialog where the parent is a dialog.    
+     */
+    public GetServiceURLDialog(JDialog parent, boolean modal)
+    {
+        super(parent, "Enter service URL", modal);
+        initComponents();
+    }
+
+    /**
+     * Get the service URL set in the dialog.
+     *
+     * @return The service URL or null if none was set
+     */
+    public String getServiceURL()
+    {
+    	return serviceURL;
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+               	
+        JLabel jlServiceURL = new JLabel("Service URL");
+        jtfServiceURL = new JTextField(15);
+
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+             
+        JLabel jlInstructions; // Instructions
+    	jlInstructions = new JLabel ("Enter service URL for key pair");
+    	jlInstructions.setFont(new Font(null, Font.PLAIN, 11));
+    	jlInstructions.setBorder(new EmptyBorder(5,5,5,5));
+    	getContentPane().add(jlInstructions, BorderLayout.NORTH);
+        
+        JPanel jpServiceURL = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpServiceURL.add(jlServiceURL);
+        jpServiceURL.add(jtfServiceURL);
+        jpServiceURL.setBorder(new EmptyBorder(5, 5, 5, 5));
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+        jpButtons.add(jbCancel);
+
+        getContentPane().add(jpServiceURL, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * OK button pressed or otherwise activated.
+     */
+    private void okPressed()
+    {
+    	serviceURL = new String(jtfServiceURL.getText());
+    	closeDialog();
+    }
+
+    /**
+     * Cancel button pressed or otherwise activated.
+     */
+    private void cancelPressed()
+    {
+    	serviceURL = null;
+        closeDialog();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/KeyPairsTableModel.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/KeyPairsTableModel.java
new file mode 100644
index 0000000..9688411
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/KeyPairsTableModel.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * 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 java.util.ArrayList;
+import java.util.TreeMap;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.table.AbstractTableModel;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.KeystoreChangedEvent;
+
+/**
+ * The table model used to display the Keystore's key pair entries.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class KeyPairsTableModel extends AbstractTableModel implements Observer<KeystoreChangedEvent> {
+
+	// Column names 
+    private String[] columnNames;
+
+    // Table data 
+    private Object[][] data;
+    
+	private CredentialManager credManager;
+    
+	private Logger logger = Logger.getLogger(KeyPairsTableModel.class);
+
+    /**
+     * Construct a new KeyPairsTableModel.
+     */
+    public KeyPairsTableModel()
+    {
+        credManager = null;
+        try{
+        	credManager = CredentialManager.getInstance();
+        }
+        catch (CMException cme){
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String sMessage = "Failed to instantiate Credential Manager. " + cme.getMessage();
+			logger.error("CM GUI: "+ sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+        }
+    	
+       	data = new Object[0][0];
+        columnNames = new String[] {
+        	"Entry Type", // type of the Keystore entry
+        	"Owner", // owner's common name
+        	"Issuer", // issuer's common name
+        	"Serial Number", // public key certificate's serial number
+        	"Last Modified", // last modified date of the entry
+            "URLs", // the invisible column holding the list of URLs associated with this entry
+            "Alias" // the invisible column holding the actual alias in the Keystore
+        	};
+        
+        try {
+			load();
+		} catch (CMException cme) {
+			String sMessage = "Failed to load key pairs";
+			logger.error(sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+		
+        // Start observing changes to the Keystore
+        credManager.addObserver(this);
+    }
+    
+    /**
+     * Load the KeyPairsTableModel with the key pair entries from the Keystore. 
+     */
+    public void load() throws CMException {
+        
+        try{
+            // Place key pair entries' aliases in a tree map to sort them
+            TreeMap<String, String> sortedAliases = new TreeMap<String, String>();  
+            	
+            ArrayList<String> aliases = credManager.getAliases(CredentialManager.KEYSTORE);
+            
+           	for (String alias: aliases){
+        		// We are only interested in key pair entries here.
+        		// Alias for such entries is constructed as "keypair#<CERT_SERIAL_NUMBER>#<CERT_COMMON_NAME>" where
+        		if (alias.startsWith("keypair#")){
+        			sortedAliases.put(alias, alias);
+        		}
+        	}   		
+        			
+            // Create one table row for each key pair entry
+            data = new Object[sortedAliases.size()][7];
+
+            // Iterate through the sorted aliases (if any), retrieving the key pair
+            // entries and populating the table model
+            int iCnt = 0;
+            for (String alias : sortedAliases.values())
+            {                
+                
+                // Populate the type column - it is set with an integer
+                // but a custom cell renderer will cause a suitable icon
+                // to be displayed
+                data[iCnt][0] = CredentialManagerUI.KEY_PAIR_ENTRY_TYPE;
+
+                // Split the alias string to extract owner, issuer and serial number 
+                // alias = "keypair#"<CERT_SUBJECT_COMMON_NAME>"#"<CERT_ISSUER_COMMON_NAME>"#"<CERT_SERIAL_NUMBER>
+                String[] aliasComponents = alias.split("#");
+                
+                // Populate the owner column extracted from the alias
+                data[iCnt][1] = aliasComponents[1];
+                
+                // Populate the issuer column extracted from the alias
+                data[iCnt][2] = aliasComponents[2];
+                
+                // Populate the serial number column extracted from the alias
+                data[iCnt][3] = aliasComponents[3];
+                
+                // Populate the modified date column ("UBER" keystore type supports creation date)
+               	data[iCnt][4] = credManager.getEntryCreationDate(CredentialManager.KEYSTORE, alias);
+
+                // Populate the invisible URLs list column
+                data[iCnt][5] = credManager.getServiceURLsForKeyPair(alias);   
+                
+                // Populate the invisible alias column
+                data[iCnt][6] = alias;  
+                
+                iCnt++;
+            }
+        }
+        catch (CMException cme){
+            throw (cme);
+        }
+
+        fireTableDataChanged();
+    }
+    
+    /**
+     * Get the number of columns in the table.
+     */
+    public int getColumnCount()
+    {
+        return columnNames.length;
+    }
+
+    /**
+     * Get the number of rows in the table.
+     */
+    public int getRowCount()
+    {
+        return data.length;
+    }
+
+    /**
+     * Get the name of the column at the given position.
+     */
+    public String getColumnName(int iCol)
+    {
+        return columnNames[iCol];
+    }
+
+    /**
+     * Get the cell value at the given row and column position.
+     */
+    public Object getValueAt(int iRow, int iCol)
+    {
+        return data[iRow][iCol];
+    }
+
+    /**
+     * Get the class at of the cells at the given column position.
+     */
+    public Class<? extends Object> getColumnClass(int iCol)
+    {
+        return getValueAt(0, iCol).getClass();
+    }
+
+    /**
+     * Is the cell at the given row and column position editable?
+     */
+    public boolean isCellEditable(int iRow, int iCol)
+    {
+        // The table is always read-only
+        return false;
+    }
+
+	public void notify(Observable<KeystoreChangedEvent> sender,
+			KeystoreChangedEvent message) throws Exception {
+
+		// reload the table
+		if (message.keystoreType.equals(CredentialManager.KEYSTORE)){
+			load();
+		}
+	}    
+
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewEditPasswordEntryDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewEditPasswordEntryDialog.java
new file mode 100644
index 0000000..536e06b
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewEditPasswordEntryDialog.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+
+/**
+ * Dialog used for editing or entering new service URL, username or password of a password entry.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class NewEditPasswordEntryDialog extends JDialog
+{
+	// 'Edit' mode constant - the dialog is in the 'edit' entry mode
+	private static final String EDIT_MODE = "Edit";
+	
+	// 'New' mode constant - the dialog is in the 'new' entry mode
+	private static final String NEW_MODE = "NEW";
+	
+	// Mode of this dialog - NEW_MODE for entering new password entry and EDIT_MODE for editting an existing password entry */
+	String mode;
+  
+    // Service URL field
+    private JTextField jtfServiceURL;
+    
+    // Username field
+    private JTextField jtfUsername;
+    
+    // First password entry field
+    private JPasswordField jpfFirstPassword;
+
+    // Password confirmation entry field
+    private JPasswordField jpfConfirmPassword;
+
+    // Stores service URL entered 
+    private String serviceURL;    
+    
+    // Stores username entered 
+    private String username;
+    
+    // Stores password entered
+    private String password;
+    
+    private Logger logger = Logger.getLogger(NewEditPasswordEntryDialog.class);
+
+    /**
+     * Creates new NewEditPasswordEntryDialog dialog where parent is a frame.
+     */
+    public NewEditPasswordEntryDialog(JFrame parent, String title,
+			boolean modal, String currentURL, String currentUsername,
+			String currentPassword)
+    {
+        super(parent, title, modal);        
+        serviceURL = currentURL;
+        username = currentUsername;
+        password = currentPassword;
+        if (serviceURL == null && username == null && password == null) // if passed values are all null
+        {
+        	mode = NEW_MODE; // dialog is for entering a new password entry
+        }
+        else{
+            mode = EDIT_MODE; // dialog is for editing an existing entry
+        }
+        initComponents();
+    }
+
+    /**
+     * Creates new NewEditPasswordEntryDialog dialog where parent is a dialog.
+     */
+    public NewEditPasswordEntryDialog(JDialog parent, String title, boolean modal, String currentURL, String currentUsername, String currentPassword)
+    {
+        super(parent, title, modal);
+        serviceURL = currentURL;
+        username = currentUsername;
+        password = currentPassword;
+        if (serviceURL == null && username == null && password == null) // if passed values are all null
+        {
+        	mode = NEW_MODE; // dialog is for entering new password entry
+        }
+        else{
+            mode = EDIT_MODE; // dialog is for editing existing entry
+        }
+        initComponents();
+    }
+    
+    
+    /**
+     * Get the username set in the dialog.
+     *
+     * @return the username
+     */
+    public String getUsername()
+    {
+        return username;
+    }
+    
+    /**
+     * Get the service URL set in the dialog.
+     *
+     * @return the service URL
+     */
+    public String getServiceURL()
+    {
+        return serviceURL;
+    }
+    
+    /**
+     * Get the password set in the dialog.
+     *
+     * @return the password
+     */
+    public String getPassword()
+    {
+    	return password;
+    }
+    
+    
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+
+        JLabel jlServiceURL = new JLabel("Service URL");
+        jlServiceURL.setBorder(new EmptyBorder(0,5,0,0));
+        
+        JLabel jlUsername = new JLabel("Username");
+        jlUsername.setBorder(new EmptyBorder(0,5,0,0));
+        
+        JLabel jlFirstPassword = new JLabel("Password");
+        jlFirstPassword.setBorder(new EmptyBorder(0,5,0,0));
+        
+        JLabel jlConfirmPassword = new JLabel("Confirm password");
+        jlConfirmPassword.setBorder(new EmptyBorder(0,5,0,0));
+               
+        jtfServiceURL = new JTextField(15);
+        //jtfServiceURL.setBorder(new EmptyBorder(0,0,0,5));
+
+        jtfUsername = new JTextField(15);
+        //jtfUsername.setBorder(new EmptyBorder(0,0,0,5));
+
+        jpfFirstPassword = new JPasswordField(15);
+        //jpfFirstPassword.setBorder(new EmptyBorder(0,0,0,5));
+
+        jpfConfirmPassword = new JPasswordField(15);
+        //jpfConfirmPassword.setBorder(new EmptyBorder(0,0,0,5));
+
+        
+        //If in EDIT_MODE - populate the fields with current values
+        if (mode.equals(EDIT_MODE)){
+            jtfServiceURL.setText(serviceURL);
+            jtfUsername.setText(username);     
+            jpfFirstPassword.setText(password);
+            jpfConfirmPassword.setText(password);
+        }
+        
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+        JPanel jpPassword = new JPanel(new GridLayout(4, 2, 5, 5));
+        jpPassword.add(jlServiceURL);
+        jpPassword.add(jtfServiceURL);
+        jpPassword.add(jlUsername);
+        jpPassword.add(jtfUsername);
+        jpPassword.add(jlFirstPassword);
+        jpPassword.add(jpfFirstPassword);
+        jpPassword.add(jlConfirmPassword);
+        jpPassword.add(jpfConfirmPassword);
+        
+        jpPassword.setBorder(new CompoundBorder(
+                new EmptyBorder(10, 10, 10, 10), new EtchedBorder()));
+        
+        jpPassword.setMinimumSize(new Dimension(300,100));
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+        jpButtons.add(jbCancel);
+
+        getContentPane().add(jpPassword, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * Checks for the following:
+     * <ul>
+     *     <li>That the user has supplied a non empty service URL
+     *     <li>That the user has supplied a non empty username
+     *     <li>That the user has supplied and confirmed a non empty password
+     *     <li>That the entry with the same URL already does not exist in the Keystore
+     * </ul>
+     * and stores the new password in this object.
+     *
+     * @return true - if the user's dialog entry matches the above criteria, false otherwise
+     */
+    private boolean checkControls()
+    {
+    	serviceURL = new String(jtfServiceURL.getText());
+    	if (serviceURL.length() == 0) {
+            JOptionPane.showMessageDialog(this,
+                "Service URL cannot be empty", 
+                "Credential Manager Warning",
+                JOptionPane.WARNING_MESSAGE);
+               
+            return false;
+    	}
+    	
+    	username = new String(jtfUsername.getText());
+    	if (username.length() == 0){
+            JOptionPane.showMessageDialog(this,
+                "Username cannot be empty", 
+                "Credential Manager Warning",
+                JOptionPane.WARNING_MESSAGE);
+               
+            return false;
+    	}
+    	   	
+    	String sFirstPassword = new String(jpfFirstPassword.getPassword());
+        String sConfirmPassword = new String(jpfConfirmPassword.getPassword());
+
+    	if ((sFirstPassword.length() > 0) && (sFirstPassword.equals(sConfirmPassword))) { // passwords the same and non-empty
+    		password = sFirstPassword;
+        }
+        else if ((sFirstPassword.length() == 0) && (sFirstPassword.equals(sConfirmPassword))){ // passwords match but are empty
+
+            JOptionPane.showMessageDialog(this,
+                "Password cannot be empty", 
+                "Credential Manager Warning",
+                JOptionPane.WARNING_MESSAGE);
+
+            return false;        	
+        }
+        else{ // passwords do not match
+            JOptionPane.showMessageDialog(this,
+                "Passwords do not match", 
+                "Credential Manager Warning",
+                JOptionPane.WARNING_MESSAGE);
+
+            return false;            	
+        }
+    	
+		// Check if the entered URL is already associated with another key pair entry in the Keystore
+    	CredentialManager credManager = null;
+    	try {
+			credManager = CredentialManager.getInstance();
+		} catch (CMException cme) {
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String exMessage = "Failed to instantiate Credential Manager";
+			logger.error(exMessage, cme);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), exMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+   	
+    	HashMap<String, ArrayList<String>> urlMap = credManager.getServiceURLsforKeyPairs();
+       	if (urlMap != null){ // should not be null really (although can be empty). Check anyway.
+        	Set<String> aliases = urlMap.keySet();
+        	for (Iterator<String> i = aliases.iterator(); i.hasNext(); ){
+        		String alias = (String) i.next();
+        		// Check if url list for this alias contains the newly entered url
+        		ArrayList<String> urls = (ArrayList<String>) urlMap.get(alias);
+        		if (urls.contains(serviceURL)){
+            		// Warn the user and exit
+                	JOptionPane.showMessageDialog(
+                    		this, 
+                    		"The entered URL is already associated with another key pair entry",
+                			"Credential Manager Alert",
+                			JOptionPane.INFORMATION_MESSAGE);
+                	return false;
+        		}    		
+        	 }
+       	}
+    	
+    	return true;
+    }
+
+    /**
+     * OK button pressed or otherwise activated.
+     */
+    private void okPressed()
+    {
+        if (checkControls()) {
+            closeDialog();
+        }
+    }
+
+    /**
+     * Cancel button pressed or otherwise activated.
+     */
+    private void cancelPressed()
+    {
+    	// Set all fields to null to indicate that cancel button was pressed
+    	serviceURL = null;
+    	username = null;
+    	password = null;
+        closeDialog();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewKeyPairEntryDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewKeyPairEntryDialog.java
new file mode 100644
index 0000000..fac5e15
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewKeyPairEntryDialog.java
@@ -0,0 +1,564 @@
+/*******************************************************************************
+ * 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 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.HashMap;
+import java.util.Set;
+import java.util.Iterator;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.DefaultListModel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.BoxLayout;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+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.CMX509Util;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.GetServiceURLDialog;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.ViewCertDetailsDialog;
+
+/**
+ * Dialog that displays the details of all key pairs from a PKCS #12
+ * keystore allowing the user to pick one for import.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+class NewKeyPairEntryDialog extends JDialog
+{
+	// List of key pairs available for import 
+    private JList jltKeyPairs;
+
+    // Service URL text field for user to enter
+    private JList jltServiceURLs;
+    
+    // Service URL (associated with the key pair)
+    private ArrayList<String> serviceURLs;
+
+    // PKCS #12 keystore */
+    private KeyStore pkcs12KeyStore;
+
+    // Private key part of key pair chosen by the user for import 
+    private Key privateKey;
+
+    // Certificate chain part of 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;
+    
+    /**
+     * Creates new form NewKeyPairEntryDialog where the parent is a frame.
+     */
+    public NewKeyPairEntryDialog(JFrame parent, String title, boolean modal, KeyStore pkcs12KS)
+        throws CMException
+    {
+        super(parent, title, modal);
+        pkcs12KeyStore = pkcs12KS;
+        initComponents();
+    }
+
+    /**
+     * Creates new form NewKeyPairEntryDialog where the parent is a dialog.
+     */
+    public NewKeyPairEntryDialog(JDialog parent, String title, boolean modal, KeyStore pkcs12KS)
+        throws CMException
+    {
+        super(parent, title, modal);
+        pkcs12KeyStore = pkcs12KS;
+        initComponents();
+    }
+
+    /**
+     * Get the private part of the key pair chosen by the user for import.
+     *
+     * @return The private key or null if the user has not chosen a key pair
+     */
+    public Key getPrivateKey()
+    {
+        return privateKey;
+    }
+
+    /**
+     * Get the certificate chain part of the key pair chosen by the
+     * user for import.
+     *
+     * @return The certificate chain or null if the user has not
+     * chosen a key pair
+     */
+    public Certificate[] getCertificateChain()
+    {
+        return certificateChain;
+    }
+
+    /**
+     * Get the alias of the key pair chosen by the user for import.
+     * 
+     * @return the alias
+     */
+    public String getAlias()
+    {
+        return alias;
+    }
+    
+    /**
+     * Get the service URLs entered by the user.
+     * 
+     * @return list of service URLs
+     */
+    public ArrayList<String> getServiceURLs()
+    {
+        return serviceURLs;
+    }
+    
+    /**
+     * Initialise the dialog's GUI components.
+     *
+     * @throws CMException A problem was encountered importing a key pair
+     */
+    private void initComponents()
+        throws CMException
+    {
+        // Instructions
+        JLabel jlInstructions = new JLabel("Select a key pair for import:");
+        jlInstructions.setFont(new Font(null, Font.PLAIN, 11));
+        jlInstructions.setBorder(new EmptyBorder(5,5,5,5));
+        JPanel jpInstructions = new JPanel(new BorderLayout());
+        jpInstructions.add(jlInstructions, BorderLayout.WEST);
+
+        // Import button
+        final JButton jbImport = new JButton("Import");
+        jbImport.setEnabled(false);
+        jbImport.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                importPressed();
+            }
+        });
+
+        // Certificate details button
+        final JButton jbCertificateDetails = new JButton("Certificate Details");
+        jbCertificateDetails.setEnabled(false);
+        jbCertificateDetails.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                certificateDetailsPressed();
+            }
+        });
+
+        // List to hold keystore's key pairs
+        jltKeyPairs = new JList();
+        jltKeyPairs.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        jltKeyPairs.addListSelectionListener(new ListSelectionListener()
+        {
+            public void valueChanged(ListSelectionEvent evt)
+            {	
+                if (jltKeyPairs.getSelectedIndex() == -1) {
+                    jbImport.setEnabled(false);
+                    jbCertificateDetails.setEnabled(false);
+                }
+                else {
+                    jbImport.setEnabled(true);
+                    jbCertificateDetails.setEnabled(true);
+                }
+            }
+        });
+
+        // Put the key list into a scroll pane
+        JScrollPane jspKeyPairs = new JScrollPane(jltKeyPairs,
+            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        jspKeyPairs.getViewport().setBackground(jltKeyPairs.getBackground());
+        
+        // Service URLs list
+        // Label
+        JLabel jlServiceURL = new JLabel ("Service URLs the key pair will be used for:");
+        jlServiceURL.setFont(new Font(null, Font.PLAIN, 11));
+        jlServiceURL.setBorder(new EmptyBorder(5,5,5,5));           
+        // New empty service URLs list
+        DefaultListModel jltModel = new DefaultListModel();
+        jltServiceURLs = new JList(jltModel); 
+        // 'Add' service URL button
+        JButton addButton = new JButton("Add");
+        addButton.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent evt)
+            {
+            	addServiceURLPressed();
+            }       	
+        });
+        addButton.setEnabled(true);
+        // 'Remove' service URL button
+        final JButton removeButton = new JButton("Remove");
+        removeButton.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent evt)
+            {
+            	// get selected indices
+            	int[] selected = jltServiceURLs.getSelectedIndices();
+            	for (int i = selected.length -1; i>=0 ; i--){
+            		 ((DefaultListModel) jltServiceURLs.getModel()).remove(selected[i]);
+            	}
+            }       	
+        });
+        removeButton.setEnabled(false);
+        jltServiceURLs.addListSelectionListener(new ListSelectionListener()
+        {
+            public void valueChanged(ListSelectionEvent evt)
+            {
+                if (jltServiceURLs.getSelectedIndex() == -1) {
+                	removeButton.setEnabled(false);
+                }
+                else {
+                	removeButton.setEnabled(true);
+                }
+            }
+        });
+        // Scroll pane for service URLs list
+        JScrollPane jspServiceURLs = new JScrollPane(jltServiceURLs,
+                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        jspServiceURLs.getViewport().setBackground(jltServiceURLs.getBackground());
+        
+        // Panel for Add and Remove buttons
+        JPanel jpServiceURLsButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpServiceURLsButtons.add(addButton);
+        jpServiceURLsButtons.add(removeButton);
+        
+        // Panel to hold the list scroll pane and Add/Remove buttons panel
+        JPanel jpServiceURLs = new JPanel(new BorderLayout());
+        jpServiceURLs.add(jlServiceURL, BorderLayout.NORTH);
+        jpServiceURLs.add(jspServiceURLs, BorderLayout.CENTER);
+        jpServiceURLs.add(jpServiceURLsButtons, BorderLayout.SOUTH);
+        
+        // Put all the key pair components together
+        JPanel jpKeyPairs = new JPanel(); // BoxLayout
+        jpKeyPairs.setLayout(new BoxLayout(jpKeyPairs, BoxLayout.Y_AXIS));
+        //jpKeyPairs.setPreferredSize(new Dimension(400, 200));
+        jpKeyPairs.setBorder(new CompoundBorder(new CompoundBorder(
+            new EmptyBorder(5, 5, 5, 5), new EtchedBorder()), new EmptyBorder(
+            5, 5, 5, 5)));
+   
+        jpInstructions.setAlignmentY(JPanel.LEFT_ALIGNMENT);
+        jpKeyPairs.add(jpInstructions);
+        jspKeyPairs.setAlignmentY(JPanel.LEFT_ALIGNMENT);
+        jpKeyPairs.add(jspKeyPairs);
+        jbCertificateDetails.setAlignmentY(JPanel.RIGHT_ALIGNMENT);
+        jpKeyPairs.add(jbCertificateDetails);
+        jpServiceURLs.setAlignmentY(JPanel.LEFT_ALIGNMENT);
+        jpKeyPairs.add(jpServiceURLs);
+
+        // Cancel button
+        final JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbImport);
+        jpButtons.add(jbCancel);
+
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(jpKeyPairs, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        // Populate the list
+        populateList();
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbImport);
+
+        pack();
+
+    }
+
+    /**
+     * Populate the key pair list with the PKCS #12 keystore's key
+     * pair aliases.
+     *
+     * @throws CMException Problem accessing the keystore's entries
+     */
+    private void populateList()
+        throws CMException
+    {
+        try {
+        	ArrayList<String> vKeyPairAliases = new ArrayList<String>();
+
+            // For each entry in the keystore...
+            for (Enumeration<String> aliases = pkcs12KeyStore.aliases(); aliases.hasMoreElements();)
+            {
+                // Get alias
+                String sAlias = (String) aliases.nextElement();
+
+                // Add the alias to the list if the entry has a key
+                // and certificates
+                if (pkcs12KeyStore.isKeyEntry(sAlias)) {
+                	pkcs12KeyStore.getKey(sAlias, new char[] {});
+                    Certificate[] certs = pkcs12KeyStore.getCertificateChain(sAlias);
+
+                    if (certs != null && certs.length != 0) {
+                        vKeyPairAliases.add(sAlias);
+                    }
+                }
+            }
+
+            if (vKeyPairAliases.size() > 0) {
+                jltKeyPairs.setListData(vKeyPairAliases.toArray());
+                jltKeyPairs.setSelectedIndex(0);
+            }
+            else {
+                // No key pairs available...
+                jltKeyPairs.setListData(new String[] { "-- No key pairs present in the Credential Store --" });
+                jltKeyPairs.setEnabled(false);
+            }
+        }
+        catch (GeneralSecurityException ex) {
+            throw new CMException("Problem occured while accessing PKCS #12 keystore's entries.",
+                ex);
+        }
+    }
+
+    /**
+     * 'Certificate Details' button pressed. Display the selected key
+     * pair's certificate.
+     */
+    private void certificateDetailsPressed()
+    {
+        try {        	
+            
+        	String sAlias = (String) jltKeyPairs.getSelectedValue();
+
+            assert sAlias != null;
+
+            //Convert the certificate object into an X509Certificate object.
+             X509Certificate cert = CMX509Util.convertCertificate(pkcs12KeyStore.getCertificate(sAlias));
+
+            // Supply the certificate to the view certificate dialog
+            ViewCertDetailsDialog viewCertificateDialog = new ViewCertDetailsDialog(this,
+            		"Certificate details", 
+            		true, 
+            		(X509Certificate) cert,
+            		null);
+            viewCertificateDialog.setLocationRelativeTo(this);
+            viewCertificateDialog.setVisible(true);
+            
+        }
+        catch (Exception ex) {
+        	
+            JOptionPane.showMessageDialog(this,
+                    "Failed to obtain certificate details to show.", 
+                    "Credential Manager Alert",
+                    JOptionPane.WARNING_MESSAGE);
+            closeDialog();
+        }
+    }
+
+
+    /**
+     * Import button pressed by user. Store the selected key pair's
+     * private and public parts and service URLs and close the dialog.
+     */
+    public void importPressed()
+    {
+    	// Get Service URLs
+    	serviceURLs = new ArrayList<String>();
+    	Enumeration<?> URLs = (((DefaultListModel) jltServiceURLs.getModel()).elements());
+    	 for( ; URLs.hasMoreElements(); ){
+    		 serviceURLs.add((String) URLs.nextElement());
+    	 }
+        	
+        String sAlias = (String) jltKeyPairs.getSelectedValue();
+
+        assert sAlias != null;
+
+        try {
+            privateKey = pkcs12KeyStore.getKey(sAlias, new char[] {});
+            certificateChain = pkcs12KeyStore.getCertificateChain(sAlias);
+            alias = sAlias;
+        }
+        catch (Exception ex) {
+            JOptionPane.showMessageDialog(this,
+                    "Failed to load the private key and certificate chain from PKCS #12 file.", 
+                    "Credential Manager Error",
+                    JOptionPane.ERROR_MESSAGE);
+            closeDialog();
+        }
+
+        closeDialog();
+    }
+    
+    /**
+     * Add Service URL button pressed.
+     */
+    public void addServiceURLPressed(){
+    	
+    	// Display the dialog for entering service URL
+    	GetServiceURLDialog dGetServiceURL = new GetServiceURLDialog(this, true);
+        
+    	dGetServiceURL.setLocationRelativeTo(this);
+    	dGetServiceURL.setVisible(true);
+    	    	
+        String sURL = dGetServiceURL.getServiceURL();
+        
+        if (sURL == null){ // user cancelled
+        	return;
+        }
+        
+        if (sURL.length() == 0){ // user entered an empty URL
+       		// Warn the user
+        	JOptionPane.showMessageDialog(
+            		this, 
+            		"Service URL cannot be empty",
+        			"Credential Manager Alert",
+        			JOptionPane.INFORMATION_MESSAGE);
+        	return;
+        }
+        
+    	// Check if the entered URL already exist in the URL list for this key entry
+    	if (((DefaultListModel) jltServiceURLs.getModel()).contains(sURL)){
+
+    		// Warn the user
+        	JOptionPane.showMessageDialog(
+            		this, 
+            		"The entered URL already exists in the list of URLs for this key pair entry",
+        			"Credential Manager Alert",
+        			JOptionPane.INFORMATION_MESSAGE);
+        	return;
+    	}
+		
+		// Check if the entered URL is already associated with another key pair entry in the Keystore       	
+    	CredentialManager credManager = null;
+		try {
+			credManager = CredentialManager.getInstance();
+		} catch (CMException cme) {
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String sMessage = "Failed to instantiate Credential Manager. " + cme.getMessage();
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+    	// Get the lists of URLs for the alias
+    	HashMap<String, ArrayList<String>> serviceURLsMap = credManager.getServiceURLsforKeyPairs();       	
+    	if (serviceURLsMap != null){ // should not be null really (although can be empty). Check anyway.
+        	Set<String> aliases = serviceURLsMap.keySet();
+        	for (Iterator<String> i = aliases.iterator(); i.hasNext(); ){
+        		String alias = (String) i.next();
+        		// Check if service URL list for this alias contains the newly entered URL
+        		ArrayList<String> urls = (ArrayList<String>) serviceURLsMap.get(alias);
+        		if (urls.contains(sURL)){
+            		// Warn the user and exit
+                	JOptionPane.showMessageDialog(
+                    		this, 
+                    		"The entered URL is already associated with another key pair entry",
+                			"Credential Manager Alert",
+                			JOptionPane.INFORMATION_MESSAGE);
+                	return;
+        		}    		
+        	 }
+       	}
+    	
+		// Check if the entered URL is already associated with a password entry in the Keystore
+//       	ArrayList<String> urlList = (ArrayList<String>) ((CredentialManagerUI) this.getParent()).getURLsForPasswords();
+//		// Check if this url list contains the newly entered url
+//		if (urlList.contains(sURL)){
+//    		// Warn the user and exit
+//        	JOptionPane.showMessageDialog(
+//            		this, 
+//            		"The entered URL is already associated with a password entry",
+//        			"Credential Manager Alert",
+//        			JOptionPane.INFORMATION_MESSAGE);
+//        	return;
+//		}    	
+    	
+    	// Otherwise - the entered URL is not already associated with a different entry in the Keystore, 
+		// so add this URL to the list of URLs for this key pair entry
+        ((DefaultListModel) jltServiceURLs.getModel()).addElement(sURL);
+        int index = ((DefaultListModel) jltServiceURLs.getModel()).getSize() - 1;
+        // Element is appended to the list - get its index
+        jltServiceURLs.setSelectedIndex(index);
+        // Insure the newly added URL is visible
+        jltServiceURLs.ensureIndexIsVisible(index);
+    }
+
+    /**
+     * Cancel button pressed - close the dialog.
+     */
+    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;
+    	serviceURLs = null;
+        closeDialog();
+    }
+
+    /**
+     * Closes the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+    
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewKeyPairServiceDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewKeyPairServiceDialog.java
new file mode 100644
index 0000000..9c44eaf
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewKeyPairServiceDialog.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * 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 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 javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * Dialog used for entering service url.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class NewKeyPairServiceDialog extends JDialog {
+	// Service URL entry field 
+    private JTextField jtfServiceURL;
+
+    // Stores service URL entered 
+    private String sURL = null;
+
+    /**
+     * Creates new NewKeyPairServiceDialog dialog where the parent is a frame.
+     */
+    public NewKeyPairServiceDialog(JFrame parent, String title, boolean modal)
+    {
+        super(parent, title, modal);
+        initComponents();
+    }
+
+    /**
+     * Creates new NewKeyPairServiceDialog dialog where the parent is a dialog.
+     */
+    public NewKeyPairServiceDialog(JDialog parent, String title, boolean modal)
+    {
+        super(parent, title, modal);
+        initComponents();
+    }
+
+    /**
+     * Get the service URL set in the dialog.
+     *
+     * @return The service URL or null if none was set
+     */
+    public String getServiceURL()
+    {
+          return sURL;
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+        
+        JLabel jlDescription = new JLabel("Enter the service URL the key pair will be associated to");
+    	jlDescription.setFont(new Font(null, Font.PLAIN, 11));
+    	jlDescription.setBorder(new EmptyBorder(5,5,5,5));
+    	
+    	JLabel jlServiceURL= new JLabel("Service URL");
+        jtfServiceURL = new JTextField(15);
+
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+        JPanel jpServiceURL = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpServiceURL.add(jlServiceURL);
+        jpServiceURL.add(jtfServiceURL);
+        jpServiceURL.setBorder(new EmptyBorder(5, 5, 5, 5));
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+        jpButtons.add(jbCancel);
+
+    	getContentPane().add(jlDescription, BorderLayout.NORTH);
+        getContentPane().add(jpServiceURL, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * OK button pressed or otherwise activated.
+     */
+    private void okPressed()
+    {
+        sURL = jtfServiceURL.getText();
+        closeDialog();
+    }
+
+    /**
+     * Cancel button pressed or otherwise activated.
+     */
+    private void cancelPressed()
+    {
+       	// Set sURL field to null as it might have changed in the meantime
+    	// if user entered some value than pressed cancel later on
+    	sURL = null;       
+    	closeDialog();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewTrustCertsDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewTrustCertsDialog.java
new file mode 100644
index 0000000..ec14b63
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/NewTrustCertsDialog.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * 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 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.cert.X509Certificate;
+import java.util.ArrayList;
+
+import javax.security.auth.x500.X500Principal;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.BoxLayout;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import net.sf.taverna.t2.security.credentialmanager.CMX509Util;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.ViewCertDetailsDialog;
+
+/**
+ * Dialog that displays the details of all trusted certificates
+ * keystore allowing the user to pick one or more for import.
+ * 
+ * @author Alex Nenadic
+ */
+class NewTrustCertsDialog
+    extends JDialog
+{
+
+	private static final long serialVersionUID = 8702957635188643993L;
+
+	/** List of trusted certs available for import */
+    private JList jltTrustCerts;
+
+    /** List of trusted certs available for import */
+    private ArrayList<X509Certificate> availableTrustCerts = new ArrayList<X509Certificate>();
+    
+    /** List of trusted certs selected for import */
+    private ArrayList<X509Certificate> selectedTrustCerts;
+    
+    /**
+     * Creates new form NewTrustCertsDialog where the parent is a frame.
+     */
+    public NewTrustCertsDialog(JFrame parent, String title, boolean modal, ArrayList<X509Certificate> lCerts)
+    {
+        super(parent, title, modal);
+        //System.arraycopy(lCerts, 0, trustCerts, 0, lCerts.length);
+        availableTrustCerts = lCerts;
+        initComponents();
+    }
+    
+    /**
+     * Creates new form NewTrustCertsDialog where the parent is a frame.
+     */
+    public NewTrustCertsDialog(JDialog parent, String title, boolean modal, ArrayList<X509Certificate> lCerts)
+    {
+        super(parent, title, modal);
+        //System.arraycopy(lCerts, 0, trustCerts, 0, lCerts.length);
+        availableTrustCerts = lCerts;
+        initComponents();
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        // Instructions
+        JLabel jlInstructions = new JLabel("Select one or more certificates for import:");
+        jlInstructions.setFont(new Font(null, Font.PLAIN, 11));
+        jlInstructions.setBorder(new EmptyBorder(5,5,5,5));
+        JPanel jpInstructions = new JPanel(new BorderLayout());
+        jpInstructions.add(jlInstructions, BorderLayout.WEST);
+
+        // Import button
+        final JButton jbImport = new JButton("Import");
+        jbImport.setEnabled(false);
+        jbImport.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                importPressed();
+            }
+        });
+
+        // Certificate details button
+        final JButton jbCertificateDetails = new JButton("Certificate Details");
+        jbCertificateDetails.setEnabled(false);
+        jbCertificateDetails.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                certificateDetailsPressed();
+            }
+        });
+
+        // List to hold trusted certs' aliases
+        jltTrustCerts = new JList();
+        jltTrustCerts.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
+        jltTrustCerts.addListSelectionListener(new ListSelectionListener()
+        {
+            public void valueChanged(ListSelectionEvent evt)
+            {
+            	
+                if (jltTrustCerts.getSelectedIndex() == -1) {
+                    jbImport.setEnabled(false);
+                    jbCertificateDetails.setEnabled(false);
+                }
+                else {
+                    jbImport.setEnabled(true);
+                    jbCertificateDetails.setEnabled(true);
+                }
+            }
+        });
+        // Populate the list
+        // Get the certificate subjects' CNs
+        ArrayList<String> cns = new ArrayList<String>();
+        for (int i = 0; i < availableTrustCerts.size(); i++){
+        	
+    		String DN = ((X509Certificate) availableTrustCerts.get(i)).getSubjectX500Principal().getName(X500Principal.RFC2253);
+    		CMX509Util util = new CMX509Util();
+    		util.parseDN(DN);
+    		
+        	String CN = util.getCN();
+        	cns.add(i, CN);
+        }
+        jltTrustCerts.setListData(cns.toArray());
+        jltTrustCerts.setSelectedIndex(0);
+
+        // Put the list into a scroll pane
+        JScrollPane jspTrustCerts = new JScrollPane(jltTrustCerts,
+            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        jspTrustCerts.getViewport().setBackground(jltTrustCerts.getBackground());
+        
+        // Put all the trusted cert components together
+        JPanel jpTrustCerts = new JPanel(); // BoxLayout
+        jpTrustCerts.setLayout(new BoxLayout(jpTrustCerts, BoxLayout.Y_AXIS));
+        //jpKeyPairs.setPreferredSize(new Dimension(400, 200));
+        jpTrustCerts.setBorder(new CompoundBorder(new CompoundBorder(
+            new EmptyBorder(5, 5, 5, 5), new EtchedBorder()), new EmptyBorder(
+            5, 5, 5, 5)));
+   
+        jpInstructions.setAlignmentY(JPanel.LEFT_ALIGNMENT);
+        jpTrustCerts.add(jpInstructions);
+        jspTrustCerts.setAlignmentY(JPanel.LEFT_ALIGNMENT);
+        jpTrustCerts.add(jspTrustCerts);
+        jbCertificateDetails.setAlignmentY(JPanel.RIGHT_ALIGNMENT);
+        jpTrustCerts.add(jbCertificateDetails);
+
+        // Cancel button
+        final JButton jbCancel = new JButton("Cancel");
+        jbCancel.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancelPressed();
+            }
+        });
+
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbImport);
+        jpButtons.add(jbCancel);
+
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(jpTrustCerts, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbImport);
+
+        pack();
+
+    }
+
+    /**
+     * Certificate Details button pressed.  Display the selected key
+     * pair's certificate.
+     */
+    private void certificateDetailsPressed()
+    {
+        try {        	
+        	
+        	int i = jltTrustCerts.getSelectedIndex();
+            
+        	X509Certificate cert = (X509Certificate) availableTrustCerts.get(i);
+
+            // Supply the certificate to the view certificate dialog
+            ViewCertDetailsDialog viewCertificateDialog = new ViewCertDetailsDialog(this,
+            		"Certificate details", 
+            		true, 
+            		cert,
+            		null);
+            viewCertificateDialog.setLocationRelativeTo(this);
+            viewCertificateDialog.setVisible(true);
+            
+        }
+        catch (Exception ex) {
+            JOptionPane.showMessageDialog(this,
+                    "Failed to obtain certificate details to show.", 
+                    "Credential Manager Alert",
+                    JOptionPane.WARNING_MESSAGE);
+            closeDialog();
+
+        }
+    }
+
+    /**
+     * Get the trusted certificates selected for import.
+     *
+     * @return The array of trusted certificates selected for import
+     */
+    public ArrayList<X509Certificate> getTrustedCertificates()
+    {
+    	return selectedTrustCerts;
+    }
+
+   
+    /**
+     * Import button pressed by user. Store the selected trusted certs
+     * and close the dialog.
+     */
+    public void importPressed()
+    {
+    	int[] selectedValues = jltTrustCerts.getSelectedIndices();
+    	selectedTrustCerts = new ArrayList<X509Certificate>();
+    	for (int i= 0; i < selectedValues.length; i++){
+    		selectedTrustCerts.add(availableTrustCerts.get(selectedValues[i]));
+    	}
+
+        closeDialog();
+    }
+
+    
+    /**
+     * Cancel button pressed - close the dialog.
+     */
+    public void cancelPressed()
+    {
+    	// Set selectedTrustCerts to null to indicate that user cancelled
+    	selectedTrustCerts = null;
+        closeDialog();
+    }
+
+    /**
+     * Closes the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/PasswordsTableModel.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/PasswordsTableModel.java
new file mode 100644
index 0000000..155b946
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/PasswordsTableModel.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * 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 java.util.ArrayList;
+import java.util.TreeMap;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.table.AbstractTableModel;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.KeystoreChangedEvent;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.CredentialManagerUI;
+
+import org.apache.log4j.Logger;
+
+/**
+ * The table model used to display the Keystore's username/password 
+ * pair entries.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class PasswordsTableModel extends AbstractTableModel implements Observer<KeystoreChangedEvent> {
+
+	// Column names 
+    private String[] columnNames;
+
+    // Table data
+    private Object[][] data;
+
+	private CredentialManager credManager;
+	
+	private Logger logger = Logger.getLogger(PasswordsTableModel.class);
+
+    /**
+     * Construct a new PasswordsTableModel.
+     */
+    public PasswordsTableModel(){
+    	
+        credManager = null;
+        try{
+        	credManager = CredentialManager.getInstance();
+        }
+        catch (CMException cme){
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String sMessage = "Failed to instantiate Credential Manager. " + cme.getMessage();
+			logger.error("CM GUI: "+ sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+        }
+        
+    	data = new Object[0][0];
+        columnNames = new String[] {
+                "Entry Type", // type of the Keystore entry
+                "Service URL", // the service url, part of the actual alias in the Keystore
+                "Username", // username for the service, part of the password entry in the Keystore
+                "Last Modified", // last modified date of the entry
+                "Password", // the invisible column holding the password value of the password entry in the Keystore
+        		"Alias" // the invisible column holding the Keystore alias of the entry
+        };
+        
+        try {
+			load();
+		} catch (CMException cme) {
+			String sMessage = "Failed to load username and password pairs";
+			logger.error(sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+        
+        // Start observing changes to the Keystore
+        credManager.addObserver(this);
+    }
+    
+    /**
+     * Load the PasswordsTableModel with the password entries from the Keystore. 
+     */
+    public void load() throws CMException
+    {
+    	try{
+            // Place password entries' aliases in a tree map to sort them
+            TreeMap<String, String> sortedAliases = new TreeMap<String, String>();  
+            	
+            ArrayList<String> aliases = credManager.getAliases(CredentialManager.KEYSTORE);
+            
+           	for (String alias: aliases){
+        		// We are only interested in username/password entries here.
+        		// Alias for such entries is constructed as "password#"<SERVICE_URL> where
+        		// service URL is the service this username/password pair is to be used for.
+        		if (alias.startsWith("password#")){
+        			sortedAliases.put(alias, alias);
+        		}
+        	}
+
+            // Create one table row for each password entry
+            data = new Object[sortedAliases.size()][6];
+
+            // Iterate through the sorted aliases, retrieving the password
+            // entries and populating the table model
+            int iCnt = 0;
+            for (String alias : sortedAliases.values()){
+                
+                // Populate the type column - it is set with an integer
+                // but a custom cell renderer will cause a suitable icon
+                // to be displayed
+                data[iCnt][0] = CredentialManagerUI.PASSWORD_ENTRY_TYPE;
+
+                // Populate the service URL column as a substring of alias 
+                // from the first occurrence of '#' till the end of the string
+                String serviceURL = alias.substring(alias.indexOf('#')+1);
+                data[iCnt][1] = serviceURL;
+                
+                // Get the username and password pair from the Keystore. They
+                // are returned in a single string in format <USERNAME> <PASSWORD>
+                String unpassPair = credManager.getUsernameAndPasswordForService(serviceURL);
+            	String username = unpassPair.substring(0, unpassPair.indexOf(' '));
+            	String password = unpassPair.substring(unpassPair.indexOf(' ')+1);
+                
+                // Populate the username column
+                data[iCnt][2] = username;
+               
+                // Populate the last modified date column ("UBER" keystore type supports creation date)
+                data[iCnt][3] = credManager.getEntryCreationDate(CredentialManager.KEYSTORE, alias);
+                
+                // Populate the invisible password column
+                data[iCnt][4] = password; 
+                
+                // Populate the invisible alias column
+                data[iCnt][5] = alias;
+                
+                iCnt++;
+            }
+
+            fireTableDataChanged();
+    	}
+    	catch (CMException cme){
+			throw cme;
+    	}
+    }
+    
+    /**
+     * Get the number of columns in the table.
+     */
+    public int getColumnCount()
+    {
+        return columnNames.length;
+    }
+
+    /**
+     * Get the number of rows in the table.
+     */
+    public int getRowCount()
+    {
+        return data.length;
+    }
+
+    /**
+     * Get the name of the column at the given position.
+     */
+    public String getColumnName(int iCol)
+    {
+        return columnNames[iCol];
+    }
+
+    /**
+     * Get the cell value at the given row and column position.
+     */
+    public Object getValueAt(int iRow, int iCol)
+    {
+        return data[iRow][iCol];
+    }
+
+    /**
+     * Get the class at of the cells at the given column position.
+     */
+    public Class<? extends Object> getColumnClass(int iCol)
+    {
+        return getValueAt(0, iCol).getClass();
+    }
+
+    /**
+     * Is the cell at the given row and column position editable?
+     */
+    public boolean isCellEditable(int iRow, int iCol)
+    {
+        // The table is always read-only
+        return false;
+    }
+
+	public void notify(Observable<KeystoreChangedEvent> sender,
+			KeystoreChangedEvent message) throws Exception {
+		
+		// reload the table
+		if (message.keystoreType.equals(CredentialManager.KEYSTORE)){
+			load();
+		}
+	}    
+
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ProxiesTableModel.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ProxiesTableModel.java
new file mode 100644
index 0000000..fb8c998
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ProxiesTableModel.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * 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 java.math.BigInteger;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.TreeMap;
+
+import javax.security.auth.x500.X500Principal;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.table.AbstractTableModel;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CMX509Util;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.KeystoreChangedEvent;
+
+/**
+ * The table model used to display the Keystore's proxy key pair entries.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class ProxiesTableModel extends AbstractTableModel implements Observer<KeystoreChangedEvent> {
+
+	// Column names 
+    private String[] columnNames;
+
+    // Table data 
+    private Object[][] data;
+    
+	private CredentialManager credManager;
+    
+	private Logger logger = Logger.getLogger(KeyPairsTableModel.class);
+
+    /**
+     * Construct a new KeyPairsTableModel.
+     */
+    public ProxiesTableModel()
+    {
+        credManager = null;
+        try{
+        	credManager = CredentialManager.getInstance();
+        }
+        catch (CMException cme){
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String sMessage = "Failed to instantiate Credential Manager. " + cme.getMessage();
+			logger.error("CM GUI: "+ sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+        }
+    	
+       	data = new Object[0][0];
+        columnNames = new String[] {
+            	"Entry Type", // type of the Keystore entry
+            	"Owner", // owner's common name
+            	"Issuer", // issuer's common name
+            	"Serial Number", // public key certificate's serial number
+            	"Last Modified", // last modified date of the entry
+                "Alias", // the invisible column holding the actual alias in the Keystore
+        	};
+        
+        try {
+			load();
+		} catch (CMException cme) {
+			String sMessage = "Failed to load proxies";
+			logger.error(sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+		
+        // Start observing changes to the Keystore
+        credManager.addObserver(this);
+    }
+    
+    /**
+     * Load the ProxiesTableModel with the proxy entries from the Keystore. 
+     */
+    public void load() throws CMException {
+        
+        try{
+            // Place proxy entries' aliases in a tree map to sort them
+            TreeMap<String, String> sortedAliases = new TreeMap<String, String>();  
+            	
+            ArrayList<String> aliases = credManager.getAliases(CredentialManager.KEYSTORE);
+            
+           	for (String alias: aliases){
+        		// We are only interested in proxy entries here.
+        		// Alias for such entries is constructed as "proxy#<CERT_SERIAL_NUMBER>#<CERT_COMMON_NAME>" where
+        		if (alias.startsWith("cagridproxy#") || alias.startsWith("proxy#")){ // for different proxies
+        			sortedAliases.put(alias, alias);
+        		}
+        	}    		
+        			
+            // Create one table row for each proxy entry
+            data = new Object[sortedAliases.size()][6];
+
+            // Iterate through the sorted aliases (if any), retrieving the proxy
+            // entries and populating the table model
+            int iCnt = 0;
+            for (String alias : sortedAliases.values())
+            {
+            	if (alias.startsWith("cagridproxy#")){
+                                        
+                    // Populate the type column - it is set with an integer
+                    // but a custom cell renderer will cause a suitable icon
+                    // to be displayed
+                    data[iCnt][0] = CredentialManagerUI.PROXY_ENTRY_TYPE;
+
+                    X509Certificate cert = CMX509Util.convertCertificate(credManager.getCertificate(CredentialManager.KEYSTORE, alias));
+
+                    // Populate the "Owner:Serial Number" column extracted from the alias
+        			String ownerDN = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
+        			CMX509Util util = new CMX509Util();
+        			util.parseDN(ownerDN);
+                    data[iCnt][1] = util.getCN(); // owner's common name
+                    
+                    // Populate the issuer column
+                    String issuerDN = cert.getIssuerX500Principal().getName(X500Principal.RFC2253);
+                    util.parseDN(issuerDN);
+                    data[iCnt][2] = util.getCN();
+        			
+        			// Get the hexadecimal representation of the certificate's serial number
+        			String serialNumber = new BigInteger(1, cert.getSerialNumber().toByteArray()).toString(16).toUpperCase();
+                    data[iCnt][3] = serialNumber;
+                    
+                    // Populate the modified date column ("UBER" keystore type supports creation date)
+                   	data[iCnt][4] = credManager.getEntryCreationDate(CredentialManager.KEYSTORE, alias);
+                    
+                    // Populate the invisible alias column
+                    data[iCnt][5] = alias; 
+                    
+                    iCnt++;
+            	}
+            	// else if (alias.startsWith("proxy#")) {} // for some other proxies
+            }
+        }
+        catch (CMException cme){
+            throw (cme);
+        }
+
+        fireTableDataChanged();
+    }
+    
+    /**
+     * Get the number of columns in the table.
+     */
+    public int getColumnCount()
+    {
+        return columnNames.length;
+    }
+
+    /**
+     * Get the number of rows in the table.
+     */
+    public int getRowCount()
+    {
+        return data.length;
+    }
+
+    /**
+     * Get the name of the column at the given position.
+     */
+    public String getColumnName(int iCol)
+    {
+        return columnNames[iCol];
+    }
+
+    /**
+     * Get the cell value at the given row and column position.
+     */
+    public Object getValueAt(int iRow, int iCol)
+    {
+        return data[iRow][iCol];
+    }
+
+    /**
+     * Get the class at of the cells at the given column position.
+     */
+    public Class<? extends Object> getColumnClass(int iCol)
+    {
+        return getValueAt(0, iCol).getClass();
+    }
+
+    /**
+     * Is the cell at the given row and column position editable?
+     */
+    public boolean isCellEditable(int iRow, int iCol)
+    {
+        // The table is always read-only
+        return false;
+    }
+
+	public void notify(Observable<KeystoreChangedEvent> sender,
+			KeystoreChangedEvent message) throws Exception {
+
+		// reload the table
+		if (message.keystoreType.equals(CredentialManager.KEYSTORE)){
+			load();
+		}
+	}    
+
+}
+
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TableCellRenderer.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TableCellRenderer.java
new file mode 100644
index 0000000..8db788d
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TableCellRenderer.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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 java.awt.Component;
+import java.text.DateFormat;
+import java.util.Date;
+
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.border.EmptyBorder;
+import javax.swing.table.DefaultTableCellRenderer;
+
+import net.sf.taverna.t2.workbench.ui.credentialmanager.CredentialManagerUI;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.KeyPairsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.PasswordsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TableCellRenderer;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TrustedCertsTableModel;
+
+/**
+ * Custom cell renderer for the cells of the tables displaying Keystore/Truststore contents.
+ * 
+ * @author Alexandra Nenadic
+ */
+public class TableCellRenderer
+    extends DefaultTableCellRenderer
+{
+	private static final long serialVersionUID = -3983986682794010259L;
+
+	private final ImageIcon passwordEntryIcon = new ImageIcon(TableCellRenderer.class.getResource(
+	"/images/table/key_entry.png"));
+	
+	private final ImageIcon keypairEntryIcon = new ImageIcon(TableCellRenderer.class.getResource(
+	"/images/table/keypair_entry.png"));
+	
+	private final ImageIcon trustcertEntryIcon = new ImageIcon(TableCellRenderer.class.getResource(
+	"/images/table/trustcert_entry.png"));
+
+    /**
+     * Returns the rendered cell for the supplied value and column.
+     *
+     * @param jtKeyStore The JTable
+     * @param value The value to assign to the cell
+     * @param bIsSelected True if cell is selected
+     * @param iRow The row of the cell to render
+     * @param iCol The column of the cell to render
+     * @param bHasFocus If true, render cell appropriately
+     * @return The renderered cell
+     */
+    public Component getTableCellRendererComponent(JTable jtKeyStoreTable,
+        Object value, boolean bIsSelected, boolean bHasFocus, int iRow,
+        int iCol)
+    {
+        JLabel cell = (JLabel) super.getTableCellRendererComponent(jtKeyStoreTable,
+            value, bIsSelected, bHasFocus, iRow, iCol);
+
+        if (value != null){
+            // Type column - display an icon representing the type
+            if (iCol == 0) {
+                ImageIcon icon = null;
+                //The cell is in the first column of Passwords table
+                if (CredentialManagerUI.PASSWORD_ENTRY_TYPE.equals(value)) { 
+                    icon = passwordEntryIcon; //key (i.e. password) entry image
+                }
+                // The cell is in the first column of Key Pairs table
+                else if (CredentialManagerUI.KEY_PAIR_ENTRY_TYPE.equals(value)) { 
+                    icon = keypairEntryIcon; //key pair entry image
+                }
+                // The cell is in the first column of Proxies table
+                else if (CredentialManagerUI.PROXY_ENTRY_TYPE.equals(value)) { 
+                    icon = keypairEntryIcon; //key pair entry image
+                }
+                //The cell is in the first column of Trusted Certificates table
+                else if (CredentialManagerUI.TRUST_CERT_ENTRY_TYPE.equals(value)) { 
+                    icon = trustcertEntryIcon; //trust. certificate entry image
+                }
+
+                cell.setIcon(icon);
+                cell.setText("");
+                cell.setVerticalAlignment(CENTER);
+                cell.setHorizontalAlignment(CENTER);
+                
+            }
+            // Last Modified column - format date (if date supplied)        
+            else if (((jtKeyStoreTable.getModel() instanceof PasswordsTableModel) && (iCol == 3)) || 
+            	((jtKeyStoreTable.getModel() instanceof KeyPairsTableModel) && (iCol == 4))||
+            	((jtKeyStoreTable.getModel() instanceof ProxiesTableModel) && (iCol == 4))||
+            	((jtKeyStoreTable.getModel() instanceof TrustedCertsTableModel) && (iCol == 4))){
+            	if (value instanceof Date) {
+            		// Include timezone
+            		cell.setText(DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
+            			DateFormat.LONG).format((Date) value));
+            	}
+            	else {
+            		cell.setText(value.toString());
+            	}
+            }
+            // Other columns - just use their text
+            else { 
+            	cell.setText(value.toString());     	
+            }
+        }
+
+        cell.setBorder(new EmptyBorder(0, 5, 0, 5));
+
+        return cell;
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TableHeaderRenderer.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TableHeaderRenderer.java
new file mode 100644
index 0000000..2fc6cb9
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TableHeaderRenderer.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * 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 java.awt.Component;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.table.DefaultTableCellRenderer;
+
+import net.sf.taverna.t2.workbench.ui.credentialmanager.KeyPairsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.PasswordsTableModel;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TableHeaderRenderer;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.TrustedCertsTableModel;
+
+/**
+ * Custom cell renderer for the headers of the tables displaying Keystore/Truststore contents.
+ * 
+ * @author Alexandra Nenadic
+ */
+@SuppressWarnings("serial")
+public class TableHeaderRenderer extends DefaultTableCellRenderer {
+	
+	private final ImageIcon entryTypeIcon = new ImageIcon(TableHeaderRenderer.class.getResource(
+	"/images/table/entry_heading.png"));
+    
+    /**
+     * Returns the rendered header cell for the supplied value and column.
+     *
+     * @param jtKeyStore The JTable
+     * @param value The value to assign to the cell
+     * @param bIsSelected True if cell is selected
+     * @param iRow The row of the cell to render
+     * @param iCol The column of the cell to render
+     * @param bHasFocus If true, render cell appropriately
+     ** @return The renderered cell
+     */
+    public Component getTableCellRendererComponent(JTable jtKeyStoreTable,
+        Object value, boolean bIsSelected, boolean bHasFocus, int iRow,
+        int iCol)
+    {
+        // Get header renderer
+        JLabel header = (JLabel) jtKeyStoreTable.getColumnModel().getColumn(iCol).getHeaderRenderer();
+
+        // The entry type header contains an icon
+        if (iCol == 0) {
+            header.setText("");
+            header.setIcon(entryTypeIcon); // entry type icon (header for the first column of the table)
+            header.setHorizontalAlignment(CENTER);
+            header.setVerticalAlignment(CENTER);
+            header.setToolTipText("Entry type");
+
+        }
+        // All other headers contain text
+        else {
+            header.setText((String) value);
+            header.setHorizontalAlignment(LEFT);
+            
+            // Passwords table has 5 colums, Key pairs and Trusted Certificates tables have 3 each
+            if (jtKeyStoreTable.getModel() instanceof PasswordsTableModel){
+                if (iCol == 1) { //Service URL column
+                    header.setToolTipText("URL of the service username and password will be used for");
+                }
+                else if (iCol == 2){ //Username column 
+                    header.setToolTipText("Username for the service");                	
+                }
+                else if (iCol == 3){ // Last modified column
+                    header.setToolTipText("Last modification date and time");
+                }            	
+            }
+            else if(jtKeyStoreTable.getModel() instanceof KeyPairsTableModel){
+                if (iCol == 1) { //Owner
+                    header.setToolTipText("Certificate's owner");
+                }
+                else if (iCol == 2) { //Issuer
+                    header.setToolTipText("Certificate's issuer");
+                }
+                else if (iCol == 3){ //Serial number
+                    header.setToolTipText("Certificate's serial number");
+                }
+                else if(iCol == 4) { // Last modified column
+                    header.setToolTipText("Last modification date and time");
+                }         	
+            }       
+            else if(jtKeyStoreTable.getModel() instanceof ProxiesTableModel){
+                if (iCol == 1) { //Owner
+                    header.setToolTipText("Certificate's owner");
+                }
+                else if (iCol == 2) { //Issuer
+                    header.setToolTipText("Certificate's issuer");
+                }
+                else if (iCol == 3){ //Serial number
+                    header.setToolTipText("Certificate's serial number");
+                }
+                else if(iCol == 4) { // Last modified column
+                    header.setToolTipText("Last modification date and time");
+                }       	
+            } 
+            else if(jtKeyStoreTable.getModel() instanceof TrustedCertsTableModel){
+                if (iCol == 1) { //Owner
+                    header.setToolTipText("Certificate's owner");
+                }
+                else if (iCol == 2) { //Issuer
+                    header.setToolTipText("Certificate's issuer");
+                }
+                else if (iCol == 3){ //Serial number
+                    header.setToolTipText("Certificate's serial number");
+                }
+                else if(iCol == 4) { // Last modified column
+                    header.setToolTipText("Last modification date and time");
+                }        	
+            }         
+        }
+        header.setBorder(new CompoundBorder(
+            new BevelBorder(BevelBorder.RAISED), new EmptyBorder(0, 5, 0, 5)));
+
+        return header;
+    }
+}
+
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TrustedCertsTableModel.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TrustedCertsTableModel.java
new file mode 100644
index 0000000..7d7da07
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/TrustedCertsTableModel.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * 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 javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.table.AbstractTableModel;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.KeystoreChangedEvent;
+
+import java.util.ArrayList;
+import java.util.TreeMap;
+
+/**
+ * The table model used to display the Keystore's trusted certificate entries.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class TrustedCertsTableModel extends AbstractTableModel implements Observer<KeystoreChangedEvent>{
+	
+	// Column names 
+    private String[] columnNames;
+
+    // Table data 
+    private Object[][] data;
+    
+	private CredentialManager credManager;
+	
+	private Logger logger = Logger.getLogger(TrustedCertsTableModel.class);
+
+	
+    /**
+     * Construct a new TrustCertsTableModel.
+     */
+    public TrustedCertsTableModel() {
+        credManager = null;
+        try{
+        	credManager = CredentialManager.getInstance();
+        }
+        catch (CMException cme){
+			// Failed to instantiate Credential Manager - warn the user and exit
+			String sMessage = "Failed to instantiate Credential Manager. " + cme.getMessage();
+			logger.error("CM GUI: "+ sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+        }
+        
+       	data = new Object[0][0];
+        columnNames = new String[] {
+        	"Entry Type", // type of the Keystore entry
+        	"Owner", // owner's common name
+        	"Issuer", // issuer's common name
+        	"Serial Number", // public key certificate's serial number
+            "Last Modified", // last modified date of the entry
+            "Alias" // the invisible column holding the actual alias in the Keystore
+            };
+        
+        try {
+			load();
+		} catch (CMException cme) {
+			String sMessage = "Failed to load trusted certificates";
+			logger.error(sMessage);
+			cme.printStackTrace();
+			JOptionPane.showMessageDialog(new JFrame(), sMessage,
+					"Credential Manager Error", JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+		
+        // Start observing changes to the Keystore
+        credManager.addObserver(this);
+    }
+    	   
+    /**
+     * Load the TrustCertsTableModel with trusted certificate entries from the Keystore. 
+     */
+    public void load() throws CMException {
+        try{
+            // Place trusted certificate entries' aliases in a tree map to sort them
+            TreeMap<String, String> sortedAliases = new TreeMap<String, String>();  
+            	
+            ArrayList<String> aliases = credManager.getAliases(CredentialManager.TRUSTSTORE);
+            
+           	for (String alias: aliases){
+        		// We are only interested in trusted certificate entries here.
+        		// Alias for such entries is constructed as "trustedcert#<CERT_SERIAL_NUMBER>#<CERT_COMMON_NAME>"
+        		if (alias.startsWith("trustedcert#")){
+        			sortedAliases.put(alias, alias);
+        		}
+        	}
+        	
+            // Create one table row for each trusted certificate entry
+            // Each row has 4 fields - type, owner name, last modified data and the invisible alias
+            data = new Object[sortedAliases.size()][6];
+
+            // Iterate through the sorted aliases, retrieving the trusted certificate 
+            // entries and populating the table model
+            int iCnt = 0;
+            for (String alias : sortedAliases.values()){
+                // Populate the type column - it is set with an integer
+                // but a custom cell renderer will cause a suitable icon
+                // to be displayed
+                data[iCnt][0] = CredentialManagerUI.TRUST_CERT_ENTRY_TYPE;
+                
+                // Split the alias string to extract owner, issuer and serial number 
+                // alias = "trustedcert#<CERT_SUBJECT_COMMON_NAME>"#"<CERT_ISSUER_COMMON_NAME>"#"<CERT_SERIAL_NUMBER>
+                String[] aliasComponents = alias.split("#");
+       
+                // Populate the owner column extracted from the alias
+                data[iCnt][1] = aliasComponents[1];
+                
+                // Populate the issuer column extracted from the alias
+                data[iCnt][2] = aliasComponents[2];
+                
+                // Populate the serial number column extracted from the alias
+                data[iCnt][3] = aliasComponents[3];
+            	
+                // Populate the modified date column
+                data[iCnt][4] = credManager.getEntryCreationDate(CredentialManager.TRUSTSTORE, alias);
+
+                // Populate the invisible alias column
+                data[iCnt][5] = alias;
+                
+                iCnt ++;
+            }
+        }
+        catch (CMException cme){
+			 throw (cme);
+        }
+
+        fireTableDataChanged();
+    }
+    
+    /**
+     * Get the number of columns in the table.
+     *
+     * @return The number of columns
+     */
+    public int getColumnCount()
+    {
+        return columnNames.length;
+    }
+
+    /**
+     * Get the number of rows in the table.
+     *
+     * @return The number of rows
+     */
+    public int getRowCount()
+    {
+        return data.length;
+    }
+
+    /**
+     * Get the name of the column at the given position.
+     *
+     * @param iCol The column position
+     * @return The column name
+     */
+    public String getColumnName(int iCol)
+    {
+        return columnNames[iCol];
+    }
+
+    /**
+     * Get the cell value at the given row and column position.
+     *
+     * @param iRow The row position
+     * @param iCol The column position
+     * @return The cell value
+     */
+    public Object getValueAt(int iRow, int iCol)
+    {
+        return data[iRow][iCol];
+    }
+
+    /**
+     * Get the class at of the cells at the given column position.
+     *
+     * @param iCol The column position
+     * @return The column cells' class
+     */
+    public Class<? extends Object> getColumnClass(int iCol)
+    {
+        return getValueAt(0, iCol).getClass();
+    }
+
+    /**
+     * Is the cell at the given row and column position editable?
+     *
+     * @param iRow The row position
+     * @param iCol The column position
+     * @return True if the cell is editable, false otherwise
+     */
+    public boolean isCellEditable(int iRow, int iCol)
+    {
+        // The table is always read-only
+        return false;
+    }
+
+	public void notify(Observable<KeystoreChangedEvent> sender,
+			KeystoreChangedEvent message) throws Exception {
+
+		// reload the table
+		if (message.keystoreType.equals(CredentialManager.TRUSTSTORE)){
+			load();
+		}
+	}    
+
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewCaGridProxyCertDetailsDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewCaGridProxyCertDetailsDialog.java
new file mode 100644
index 0000000..1ce72ce
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewCaGridProxyCertDetailsDialog.java
@@ -0,0 +1,600 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+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.math.BigInteger;
+import java.util.HashMap;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.JSeparator;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import javax.security.auth.x500.X500Principal;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CMX509Util;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.misc.NetscapeCertType;
+
+
+/**
+ * Displays the details of a X.509 caGrid proxy certificate.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class ViewCaGridProxyCertDetailsDialog extends JDialog { 	
+	
+	// Logger
+	//private static Logger logger = Logger.getLogger(ViewCertDetailsDialog.class);
+	
+	// Stores certificate to display
+    private X509Certificate cert;
+
+	private String authNServiceURL;
+
+	private String dorianServiceURL;
+    
+
+    /**
+     * Creates new ViewCaGridProxyCertDialog dialog where the parent is a frame.
+     */
+    public ViewCaGridProxyCertDetailsDialog(JFrame parent, String title, boolean modal,
+        X509Certificate crt, String authNServiceURL, String dorianServiceURL)
+        throws CMException
+    {
+        super(parent, title, modal);
+        this.cert = crt;
+        this.authNServiceURL = authNServiceURL;
+        this.dorianServiceURL = dorianServiceURL;
+        initComponents();
+    }
+
+    /**
+     * Creates new ViewCaGridProxyCertDialog dialog where the parent is a dialog.
+     */
+    public ViewCaGridProxyCertDetailsDialog(JDialog parent, String title, boolean modal,
+        X509Certificate crt, String authNServiceURL, String dorianServiceURL)
+        throws CMException
+    {
+        super(parent, title, modal);
+        cert = crt;
+        this.authNServiceURL = authNServiceURL;
+        this.dorianServiceURL = dorianServiceURL;        
+        initComponents();
+    }
+    
+    /**
+     * Initialise the dialog's GUI components.
+     *
+     * @throws CMException A problem was encountered getting the
+     * certificates' details
+     */
+    private void initComponents()
+        throws CMException
+    {
+
+        // Certificate details:
+
+        // Grid Bag Constraints templates for labels (column 1) and 
+    	// values (column 2) of certificate details
+        GridBagConstraints gbcLabel = new GridBagConstraints();
+        gbcLabel.gridx = 0;
+        gbcLabel.ipadx = 20;
+        gbcLabel.gridwidth = 1;
+        gbcLabel.gridheight = 1;
+        gbcLabel.insets = new Insets(2, 15, 2, 2);
+        gbcLabel.anchor = GridBagConstraints.LINE_START;
+
+        GridBagConstraints gbcValue = new GridBagConstraints();
+        gbcValue.gridx = 1;
+        gbcValue.gridwidth = 1;
+        gbcValue.gridheight = 1;
+        gbcValue.insets = new Insets(2, 5, 2, 2);
+        gbcValue.anchor = GridBagConstraints.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
+        byte[] intendedUses = cert.getExtensionValue("2.16.840.1.113730.1.1"); //Netscape Certificate Type OID/*
+        JLabel jlIntendedUses = null;
+        JTextField jtfIntendedUsesValue = null;
+        JPanel jpUses = null;
+        GridBagConstraints gbc_jpUses = null;
+        if (intendedUses != null)
+        {
+         	jlIntendedUses = new JLabel("This certificate has been approved for the following uses:");
+         	jlIntendedUses.setFont(new Font(null, Font.BOLD, 11));
+         	jlIntendedUses.setBorder(new EmptyBorder(5,5,5,5));
+         	
+         	jtfIntendedUsesValue = new JTextField(45);
+         	jtfIntendedUsesValue.setText(getIntendedUses(intendedUses));
+        	jtfIntendedUsesValue.setEditable(false);
+        	jtfIntendedUsesValue.setFont(new Font(null, Font.PLAIN, 11));
+             
+        	jpUses = new JPanel(new BorderLayout()); 
+        	jpUses.add(jlIntendedUses, BorderLayout.NORTH);
+        	jpUses.add(jtfIntendedUsesValue, BorderLayout.CENTER);
+        	JSeparator jsp = new JSeparator(JSeparator.HORIZONTAL);
+        	jpUses.add(jsp, BorderLayout.SOUTH);
+        	
+        	gbc_jpUses = (GridBagConstraints) gbcLabel.clone();
+        	gbc_jpUses.gridy = 0;
+        	gbc_jpUses.gridwidth = 2; //takes two columns
+        	gbc_jpUses.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+
+        }
+
+        //Issued To
+        JLabel jlIssuedTo = new JLabel("Issued To");
+        jlIssuedTo.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlIssuedTo = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIssuedTo.gridy = 1;
+        gbc_jlIssuedTo.gridwidth = 2; //takes two columns
+        gbc_jlIssuedTo.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+        // Distinguished Name (DN)
+		String sDN = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
+		CMX509Util util = new CMX509Util();
+		util.parseDN(sDN);       
+		// Extract the CN, O, OU and EMAILADDRESS fields
+        String sCN = util.getCN();
+        String sOrg = util.getO();
+        String sOU = util.getOU();
+        //String sEMAILADDRESS = CMX509Util.getEmilAddress();
+        // Common Name (CN)
+        JLabel jlCN = new JLabel("Common Name (CN)");
+        jlCN.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlCN = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlCN.gridy = 2;
+        JLabel jlCNValue = new JLabel(sCN);
+        jlCNValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlCNValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlCNValue.gridy = 2;
+        // Organisation (O)
+        JLabel jlOrg = new JLabel("Organisation (O)");
+        jlOrg.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOrg = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlOrg.gridy = 3;
+        JLabel jlOrgValue = new JLabel(sOrg);
+        jlOrgValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOrgValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlOrgValue.gridy = 3;
+        // Organisation Unit (OU)
+        JLabel jlOU = new JLabel("Organisation Unit (OU)");
+        jlOU.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOU = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlOU.gridy = 4;
+        JLabel jlOUValue = new JLabel(sOU);
+        jlOUValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOUValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlOUValue.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 jlSN = new JLabel("Serial Number");
+        jlSN.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSN = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlSN.gridy = 6;
+        JLabel jlSNValue = new JLabel();
+        // Get the hexadecimal serial number
+        StringBuffer strBuff = new StringBuffer (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, ':');
+            }
+        }
+        jlSNValue.setText(strBuff.toString());
+        jlSNValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSNValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlSNValue.gridy = 6;
+        // Version
+        JLabel jlVersion = new JLabel("Version");
+        jlVersion.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlVersion = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlVersion.gridy = 7;
+        JLabel jlVersionValue = new JLabel(Integer.toString(cert.getVersion()));
+        jlVersionValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlVersionValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlVersionValue.gridy = 7;
+
+        // Issued By
+        JLabel jlIssuedBy = new JLabel("Issued By");
+        jlIssuedBy.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlIssuedBy = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIssuedBy.gridy = 8;
+        gbc_jlIssuedBy.gridwidth = 2; //takes two columns 
+        gbc_jlIssuedBy.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets        
+        // Distinguished Name (DN)       
+		String iDN = cert.getIssuerX500Principal().getName(X500Principal.RFC2253);
+		util.parseDN(iDN);        
+        // Extract the CN, O and OU fields
+        String iCN = util.getCN();
+        String iOrg = util.getO();
+        String iOU = util.getOU();   	
+        // Common Name (CN)
+        JLabel jlICN = new JLabel("Common Name (CN)");
+        jlICN.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlICN = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlICN.gridy = 9;
+        JLabel jlICNValue = new JLabel(iCN);
+        jlICNValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlICNValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlICNValue.gridy = 9;
+        // Organisation (O)
+        JLabel jlIOrg = new JLabel("Organisation (O)");
+        jlIOrg.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOrg = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIOrg.gridy = 10;
+        JLabel jlIOrgValue = new JLabel(iOrg);
+        jlIOrgValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOrgValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlIOrgValue.gridy = 10;
+        // Organisation Unit (OU)
+        JLabel jlIOU = new JLabel("Organisation Unit (OU)");
+        jlIOU.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOU = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIOU.gridy = 11;
+        JLabel jlIOUValue = new JLabel(iOU);
+        jlIOUValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOUValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlIOUValue.gridy = 11;       
+        // Validity
+        JLabel jlValidity = new JLabel("Validity");
+        jlValidity.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlValidity = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlValidity.gridy = 12;
+        gbc_jlValidity.gridwidth = 2; //takes two columns   
+        gbc_jlValidity.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+        //Issued On
+        JLabel jlIssuedOn = new JLabel("Issued On");
+        jlIssuedOn.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIssuedOn = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIssuedOn.gridy = 13;
+        JLabel jlIssuedOnValue = new JLabel(cert.getNotBefore().toString());
+        jlIssuedOnValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIssuedOnValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlIssuedOnValue.gridy = 13;
+        // Expires On
+        JLabel jlExpiresOn = new JLabel("Expires On");
+        jlExpiresOn.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlExpiresOn = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlExpiresOn.gridy = 14;
+        JLabel jlExpiresOnValue = new JLabel(cert.getNotAfter().toString());
+        jlExpiresOnValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlExpiresOnValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlExpiresOnValue.gridy = 14;
+
+        // Fingerprints
+        byte[] bCert;
+        try {
+            bCert = cert.getEncoded();
+        }
+        catch (CertificateEncodingException ex) {
+            throw new CMException(
+                "Could not get the encoded form of the certificate.",
+                ex);
+        }
+        JLabel jlFingerprints = new JLabel("Fingerprints");
+        jlFingerprints.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlFingerprints = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlFingerprints.gridy = 15;
+        gbc_jlFingerprints.gridwidth = 2; //takes two columns  
+        gbc_jlFingerprints.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+        // SHA-1 Fingerprint
+        JLabel jlSHA1Fingerprint = new JLabel("SHA1 Fingerprint");
+        jlSHA1Fingerprint.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSHA1Fingerprint = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlSHA1Fingerprint.gridy = 16;
+        JLabel jlSHA1FingerprintValue = new JLabel(getMessageDigest(bCert, "SHA1"));
+        jlSHA1FingerprintValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSHA1FingerprintValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlSHA1FingerprintValue.gridy = 16;
+        // MD5 Fingerprint
+        JLabel jlMD5Fingerprint = new JLabel("MD5 Fingerprint");
+        jlMD5Fingerprint.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlMD5Fingerprint = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlMD5Fingerprint.gridy = 17;
+        JLabel jlMD5FingerprintValue = new JLabel(getMessageDigest(bCert, "MD5"));
+        jlMD5FingerprintValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlMD5FingerprintValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlMD5FingerprintValue.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 jlEmpty = new JLabel("");
+        GridBagConstraints gbc_jlEmpty = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlEmpty.gridy = 18;
+        gbc_jlEmpty.gridwidth = 2; //takes two columns
+        gbc_jlEmpty.ipady = 40;
+
+        JPanel jpCertificate = new JPanel(new GridBagLayout());
+        jpCertificate.setBorder(new CompoundBorder(
+            new EmptyBorder(15, 15, 15, 15), new EtchedBorder()));
+
+        if (intendedUses != null){
+        	jpCertificate.add(jpUses, gbc_jpUses);
+        }
+        jpCertificate.add(jlIssuedTo, gbc_jlIssuedTo); // Issued To
+        jpCertificate.add(jlCN, gbc_jlCN);
+        jpCertificate.add(jlCNValue, gbc_jlCNValue);
+        jpCertificate.add(jlOrg, gbc_jlOrg);
+        jpCertificate.add(jlOrgValue, gbc_jlOrgValue);        
+        jpCertificate.add(jlOU, gbc_jlOU);
+        jpCertificate.add(jlOUValue, gbc_jlOUValue);
+        //jpCertificate.add(jlEmail, gbc_jlEmail);
+        //jpCertificate.add(jlEmailValue, gbc_jlEmailValue);
+        jpCertificate.add(jlSN, gbc_jlSN);
+        jpCertificate.add(jlSNValue, gbc_jlSNValue);
+        jpCertificate.add(jlVersion, gbc_jlVersion);
+        jpCertificate.add(jlVersionValue, gbc_jlVersionValue);
+        jpCertificate.add(jlIssuedBy, gbc_jlIssuedBy); //Issued By
+        jpCertificate.add(jlICN, gbc_jlICN);
+        jpCertificate.add(jlICNValue, gbc_jlICNValue);
+        jpCertificate.add(jlIOrg, gbc_jlIOrg);
+        jpCertificate.add(jlIOrgValue, gbc_jlIOrgValue);        
+        jpCertificate.add(jlIOU, gbc_jlIOU);
+        jpCertificate.add(jlIOUValue, gbc_jlIOUValue);
+        jpCertificate.add(jlValidity, gbc_jlValidity); //Validity
+        jpCertificate.add(jlIssuedOn, gbc_jlIssuedOn);
+        jpCertificate.add(jlIssuedOnValue, gbc_jlIssuedOnValue);
+        jpCertificate.add(jlExpiresOn, gbc_jlExpiresOn);
+        jpCertificate.add(jlExpiresOnValue, gbc_jlExpiresOnValue); 
+        jpCertificate.add(jlFingerprints, gbc_jlFingerprints); //Fingerprints
+        jpCertificate.add(jlSHA1Fingerprint, gbc_jlSHA1Fingerprint);
+        jpCertificate.add(jlSHA1FingerprintValue, gbc_jlSHA1FingerprintValue);
+        jpCertificate.add(jlMD5Fingerprint, gbc_jlMD5Fingerprint);
+        jpCertificate.add(jlMD5FingerprintValue, gbc_jlMD5FingerprintValue);
+        jpCertificate.add(jlEmpty, gbc_jlEmpty); //Empty label to get some vertical space on the frame
+
+        // List of AuthN and Dorian URLs
+        JPanel jpAuthNDorianURLs = new JPanel(new BorderLayout());
+        jpAuthNDorianURLs.setBorder(new CompoundBorder(
+                    new EmptyBorder(0, 15, 0, 15), new EtchedBorder()));
+        // Label
+        JLabel jlServiceURLs = new JLabel ("The proxy has been obtained using:");
+        jlServiceURLs.setFont(new Font(null, Font.BOLD, 11));
+        jlServiceURLs.setBorder(new EmptyBorder(5,5,5,5));    
+  
+    	JPanel jpURLs = new JPanel();
+    	jpURLs.setLayout(new BoxLayout(jpURLs, BoxLayout.Y_AXIS));
+        JLabel jlAuthNServiceURL = new JLabel("Authentication Service");
+        jlAuthNServiceURL.setFont(new Font(null, Font.PLAIN, 11));
+        jlAuthNServiceURL.setAlignmentX(Component.LEFT_ALIGNMENT);
+        jlAuthNServiceURL.setBorder(new EmptyBorder(5,5,0,5));    
+
+        JLabel jlDorianServiceURL = new JLabel("Dorian Service");
+        jlDorianServiceURL.setFont(new Font(null, Font.PLAIN, 11));
+        jlDorianServiceURL.setAlignmentX(Component.LEFT_ALIGNMENT);
+        jlDorianServiceURL.setBorder(new EmptyBorder(5,5,0,5));    
+
+        JTextField jtfAuthNServiceURL = new JTextField(25);
+        jtfAuthNServiceURL.setEditable(false);
+        jtfAuthNServiceURL.setText(authNServiceURL);
+        jtfAuthNServiceURL.setFont(new Font(null, Font.PLAIN, 11));
+        jtfAuthNServiceURL.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+        JTextField jtfDorianServiceURL = new JTextField(25);
+        jtfDorianServiceURL.setEditable(false);
+        jtfDorianServiceURL.setText(dorianServiceURL);
+        jtfDorianServiceURL.setFont(new Font(null, Font.PLAIN, 11));
+        jtfDorianServiceURL.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+        jpURLs.add(jlAuthNServiceURL);
+        jpURLs.add(jtfAuthNServiceURL);
+        jpURLs.add(jlDorianServiceURL);
+        jpURLs.add(jtfDorianServiceURL);
+
+        jpAuthNDorianURLs.add(jlServiceURLs, BorderLayout.NORTH);
+        jpAuthNDorianURLs.add(jpURLs, BorderLayout.CENTER);
+               
+        // OK button
+        JPanel jpOK = new JPanel(new FlowLayout(FlowLayout.CENTER));
+
+        final JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        jpOK.add(jbOK);
+         
+        // Put it all together (panel with URL list is already added, if it was not null)
+        getContentPane().add(jpCertificate, BorderLayout.NORTH);
+        getContentPane().add(jpAuthNDorianURLs, BorderLayout.CENTER);
+        getContentPane().add(jpOK, BorderLayout.SOUTH);
+
+        // Resizing wreaks havoc
+        setResizable(false);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+
+        SwingUtilities.invokeLater(new Runnable()
+        {
+            public void run()
+            {
+                jbOK.requestFocus();
+            }
+        });
+    }
+    
+    /**
+     * Get the digest of a message as a formatted String.
+     *
+     * @param bMessage The message to digest
+     * @param digestType The message digest algorithm
+     * @return The message digest
+     * @throws CMException If there was a problem generating the message
+     * digest
+     */
+    public static String getMessageDigest(byte[] bMessage,
+        String digestType)
+        throws CMException
+    {
+        // Create message digest object using the supplied algorithm
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance(digestType);
+        }
+        catch (NoSuchAlgorithmException ex) {
+            throw new CMException("Failed to create message digest.", ex);
+        }
+
+        // Create raw message digest
+        byte[] bFingerPrint = messageDigest.digest(bMessage);
+
+        // Place the raw message digest into a StringBuffer as a Hex number
+        StringBuffer strBuff = new StringBuffer(
+            new BigInteger(1, bFingerPrint).toString(16).toUpperCase());
+
+        // Odd number of characters so add in a padding "0"
+        if ((strBuff.length() % 2) != 0) {
+            strBuff.insert(0, '0');
+        }
+
+        // Place colons at every two hex characters
+        if (strBuff.length() > 2) {
+            for (int iCnt = 2; iCnt < strBuff.length(); iCnt += 3) {
+                strBuff.insert(iCnt, ':');
+            }
+        }
+
+        // Return the formatted message digest
+        return strBuff.toString();
+    }
+    
+    /**
+     * Gets the intended certificate uses, i.e. Netscape Certificate Type extension (2.16.840.1.113730.1.1) 
+     * value as a string
+     * @param value Extension value as a DER-encoded OCTET string
+     * @return Extension value as a string
+     */
+    private String getIntendedUses(byte[] value)
+    {
+    	
+        // Netscape Certificate Types (2.16.840.1.113730.1.1)
+        int[] INTENDED_USES = new int[] {
+            NetscapeCertType.sslClient,
+            NetscapeCertType.sslServer,
+            NetscapeCertType.smime,
+            NetscapeCertType.objectSigning,
+            NetscapeCertType.reserved,
+            NetscapeCertType.sslCA,
+            NetscapeCertType.smimeCA,
+            NetscapeCertType.objectSigningCA,
+        };
+        
+        // Netscape Certificate Type strings (2.16.840.1.113730.1.1)
+        HashMap<String, String> INTENDED_USES_STRINGS = new HashMap<String, String> ();
+        INTENDED_USES_STRINGS.put("128", "SSL Client");
+        INTENDED_USES_STRINGS.put("64", "SSL Server");
+        INTENDED_USES_STRINGS.put("32", "S/MIME");
+        INTENDED_USES_STRINGS.put("16", "Object Signing");
+        INTENDED_USES_STRINGS.put("8", "Reserved");
+        INTENDED_USES_STRINGS.put("4", "SSL CA");
+        INTENDED_USES_STRINGS.put("2", "S/MIME CA");
+        INTENDED_USES_STRINGS.put("1", "Object Signing CA");
+        
+        
+        // Get octet string from extension value
+        ASN1OctetString fromByteArray = new DEROctetString(value);
+		byte[] octets = fromByteArray.getOctets();            
+    	DERBitString fromByteArray2 = new DERBitString(octets);
+		int val = new NetscapeCertType(fromByteArray2).intValue();
+        StringBuffer strBuff = new StringBuffer();
+        for (int i = 0, len = INTENDED_USES.length; i < len; i++) {
+            int use = INTENDED_USES[i];
+            if ((val & use) == use) {
+                strBuff.append(INTENDED_USES_STRINGS.get(String.valueOf(use))+", \n");
+            }
+        }
+        // remove the last ", \n" from the end of the buffer
+        String str = strBuff.toString();
+        str = str.substring(0, str.length()-3);
+        return str;
+    }
+    
+    /**
+     * OK button pressed.
+     */
+    private void okPressed()
+    {
+        closeDialog();
+    }
+
+    /**
+     * Closes the View Certificate Entry dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewCertDetailsDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewCertDetailsDialog.java
new file mode 100644
index 0000000..1f20898
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewCertDetailsDialog.java
@@ -0,0 +1,592 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+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.math.BigInteger;
+import java.util.HashMap;
+
+import javax.swing.DefaultListModel;
+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.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.JSeparator;
+
+import java.util.ArrayList;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import javax.security.auth.x500.X500Principal;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CMX509Util;
+
+//import org.apache.log4j.Logger;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.misc.NetscapeCertType;
+
+
+/**
+ * Displays the details of a X.509 certificate.
+ * 
+ * @author Alex Nenadic
+ */
+@SuppressWarnings("serial")
+public class ViewCertDetailsDialog
+    extends JDialog
+{ 	
+	// Logger
+	//private static Logger logger = Logger.getLogger(ViewCertDetailsDialog.class);
+	
+	// Stores certificate to display 
+    private X509Certificate cert;
+    
+    // Stores list of serviceURLs to display 
+    private  ArrayList<String> serviceURLs;
+
+    /**
+     * Creates new ViewCertDetailsDialog dialog where the parent is a frame.
+     */
+    public ViewCertDetailsDialog(JFrame parent, String title, boolean modal,
+        X509Certificate crt, ArrayList<String> serviceURLs)
+        throws CMException
+    {
+        super(parent, title, modal);
+        this.cert = crt;
+        this.serviceURLs = serviceURLs;
+        initComponents();
+    }
+
+    /**
+     * Creates new ViewCertDetailsDialog dialog where the parent is a dialog.
+     */
+    public ViewCertDetailsDialog(JDialog parent, String title, boolean modal,
+        X509Certificate crt, ArrayList<String> urlList)
+        throws CMException
+    {
+        super(parent, title, modal);
+        cert = crt;
+        serviceURLs = urlList;
+        initComponents();
+    }
+    
+    /**
+     * Initialise the dialog's GUI components.
+     *
+     * @throws CMException A problem was encountered getting the
+     * certificates' details
+     */
+    private void initComponents()
+        throws CMException
+    {
+
+        // Certificate details:
+
+        // Grid Bag Constraints templates for labels (column 1) and 
+    	// values (column 2) of certificate details
+        GridBagConstraints gbcLabel = new GridBagConstraints();
+        gbcLabel.gridx = 0;
+        gbcLabel.ipadx = 20;
+        gbcLabel.gridwidth = 1;
+        gbcLabel.gridheight = 1;
+        gbcLabel.insets = new Insets(2, 15, 2, 2);
+        gbcLabel.anchor = GridBagConstraints.LINE_START;
+
+        GridBagConstraints gbcValue = new GridBagConstraints();
+        gbcValue.gridx = 1;
+        gbcValue.gridwidth = 1;
+        gbcValue.gridheight = 1;
+        gbcValue.insets = new Insets(2, 5, 2, 2);
+        gbcValue.anchor = GridBagConstraints.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
+        byte[] intendedUses = cert.getExtensionValue("2.16.840.1.113730.1.1"); //Netscape Certificate Type OID/*
+        JLabel jlIntendedUses = null;
+        JTextField jtfIntendedUsesValue = null;
+        JPanel jpUses = null;
+        GridBagConstraints gbc_jpUses = null;
+        if (intendedUses != null)
+        {
+         	jlIntendedUses = new JLabel("This certificate has been approved for the following uses:");
+         	jlIntendedUses.setFont(new Font(null, Font.BOLD, 11));
+         	jlIntendedUses.setBorder(new EmptyBorder(5,5,5,5));
+         	
+         	jtfIntendedUsesValue = new JTextField(45);
+         	jtfIntendedUsesValue.setText(getIntendedUses(intendedUses));
+        	jtfIntendedUsesValue.setEditable(false);
+        	jtfIntendedUsesValue.setFont(new Font(null, Font.PLAIN, 11));
+             
+        	jpUses = new JPanel(new BorderLayout()); 
+        	jpUses.add(jlIntendedUses, BorderLayout.NORTH);
+        	jpUses.add(jtfIntendedUsesValue, BorderLayout.CENTER);
+        	JSeparator jsp = new JSeparator(JSeparator.HORIZONTAL);
+        	jpUses.add(jsp, BorderLayout.SOUTH);
+        	
+        	gbc_jpUses = (GridBagConstraints) gbcLabel.clone();
+        	gbc_jpUses.gridy = 0;
+        	gbc_jpUses.gridwidth = 2; //takes two columns
+        	gbc_jpUses.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+
+        }
+
+        //Issued To
+        JLabel jlIssuedTo = new JLabel("Issued To");
+        jlIssuedTo.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlIssuedTo = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIssuedTo.gridy = 1;
+        gbc_jlIssuedTo.gridwidth = 2; //takes two columns
+        gbc_jlIssuedTo.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+        // Distinguished Name (DN)
+		String sDN = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
+		CMX509Util util = new CMX509Util();
+		util.parseDN(sDN);       
+		// Extract the CN, O, OU and EMAILADDRESS fields
+        String sCN = util.getCN();
+        String sOrg = util.getO();
+        String sOU = util.getOU();
+        //String sEMAILADDRESS = CMX509Util.getEmilAddress();
+        // Common Name (CN)
+        JLabel jlCN = new JLabel("Common Name (CN)");
+        jlCN.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlCN = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlCN.gridy = 2;
+        JLabel jlCNValue = new JLabel(sCN);
+        jlCNValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlCNValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlCNValue.gridy = 2;
+        // Organisation (O)
+        JLabel jlOrg = new JLabel("Organisation (O)");
+        jlOrg.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOrg = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlOrg.gridy = 3;
+        JLabel jlOrgValue = new JLabel(sOrg);
+        jlOrgValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOrgValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlOrgValue.gridy = 3;
+        // Organisation Unit (OU)
+        JLabel jlOU = new JLabel("Organisation Unit (OU)");
+        jlOU.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOU = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlOU.gridy = 4;
+        JLabel jlOUValue = new JLabel(sOU);
+        jlOUValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlOUValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlOUValue.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 jlSN = new JLabel("Serial Number");
+        jlSN.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSN = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlSN.gridy = 6;
+        JLabel jlSNValue = new JLabel();
+        // Get the hexadecimal serial number
+        StringBuffer strBuff = new StringBuffer (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, ':');
+            }
+        }
+        jlSNValue.setText(strBuff.toString());
+        jlSNValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSNValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlSNValue.gridy = 6;
+        // Version
+        JLabel jlVersion = new JLabel("Version");
+        jlVersion.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlVersion = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlVersion.gridy = 7;
+        JLabel jlVersionValue = new JLabel(Integer.toString(cert.getVersion()));
+        jlVersionValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlVersionValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlVersionValue.gridy = 7;
+
+        // Issued By
+        JLabel jlIssuedBy = new JLabel("Issued By");
+        jlIssuedBy.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlIssuedBy = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIssuedBy.gridy = 8;
+        gbc_jlIssuedBy.gridwidth = 2; //takes two columns 
+        gbc_jlIssuedBy.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets        
+        // Distinguished Name (DN)       
+		String iDN = cert.getIssuerX500Principal().getName(X500Principal.RFC2253);
+		util.parseDN(iDN);        
+        // Extract the CN, O and OU fields
+        String iCN = util.getCN();
+        String iOrg = util.getO();
+        String iOU = util.getOU();   	
+        // Common Name (CN)
+        JLabel jlICN = new JLabel("Common Name (CN)");
+        jlICN.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlICN = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlICN.gridy = 9;
+        JLabel jlICNValue = new JLabel(iCN);
+        jlICNValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlICNValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlICNValue.gridy = 9;
+        // Organisation (O)
+        JLabel jlIOrg = new JLabel("Organisation (O)");
+        jlIOrg.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOrg = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIOrg.gridy = 10;
+        JLabel jlIOrgValue = new JLabel(iOrg);
+        jlIOrgValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOrgValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlIOrgValue.gridy = 10;
+        // Organisation Unit (OU)
+        JLabel jlIOU = new JLabel("Organisation Unit (OU)");
+        jlIOU.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOU = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIOU.gridy = 11;
+        JLabel jlIOUValue = new JLabel(iOU);
+        jlIOUValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIOUValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlIOUValue.gridy = 11;       
+        // Validity
+        JLabel jlValidity = new JLabel("Validity");
+        jlValidity.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlValidity = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlValidity.gridy = 12;
+        gbc_jlValidity.gridwidth = 2; //takes two columns   
+        gbc_jlValidity.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+        //Issued On
+        JLabel jlIssuedOn = new JLabel("Issued On");
+        jlIssuedOn.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIssuedOn = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlIssuedOn.gridy = 13;
+        JLabel jlIssuedOnValue = new JLabel(cert.getNotBefore().toString());
+        jlIssuedOnValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlIssuedOnValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlIssuedOnValue.gridy = 13;
+        // Expires On
+        JLabel jlExpiresOn = new JLabel("Expires On");
+        jlExpiresOn.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlExpiresOn = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlExpiresOn.gridy = 14;
+        JLabel jlExpiresOnValue = new JLabel(cert.getNotAfter().toString());
+        jlExpiresOnValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlExpiresOnValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlExpiresOnValue.gridy = 14;
+
+        // Fingerprints
+        byte[] bCert;
+        try {
+            bCert = cert.getEncoded();
+        }
+        catch (CertificateEncodingException ex) {
+            throw new CMException(
+                "Could not get the encoded form of the certificate.",
+                ex);
+        }
+        JLabel jlFingerprints = new JLabel("Fingerprints");
+        jlFingerprints.setFont(new Font(null, Font.BOLD, 11));
+        GridBagConstraints gbc_jlFingerprints = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlFingerprints.gridy = 15;
+        gbc_jlFingerprints.gridwidth = 2; //takes two columns  
+        gbc_jlFingerprints.insets = new Insets(5, 5, 5, 5);//has slightly bigger insets
+        // SHA-1 Fingerprint
+        JLabel jlSHA1Fingerprint = new JLabel("SHA1 Fingerprint");
+        jlSHA1Fingerprint.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSHA1Fingerprint = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlSHA1Fingerprint.gridy = 16;
+        JLabel jlSHA1FingerprintValue = new JLabel(getMessageDigest(bCert, "SHA1"));
+        jlSHA1FingerprintValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlSHA1FingerprintValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlSHA1FingerprintValue.gridy = 16;
+        // MD5 Fingerprint
+        JLabel jlMD5Fingerprint = new JLabel("MD5 Fingerprint");
+        jlMD5Fingerprint.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlMD5Fingerprint = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlMD5Fingerprint.gridy = 17;
+        JLabel jlMD5FingerprintValue = new JLabel(getMessageDigest(bCert, "MD5"));
+        jlMD5FingerprintValue.setFont(new Font(null, Font.PLAIN, 11));
+        GridBagConstraints gbc_jlMD5FingerprintValue = (GridBagConstraints) gbcValue.clone();
+        gbc_jlMD5FingerprintValue.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 jlEmpty = new JLabel("");
+        GridBagConstraints gbc_jlEmpty = (GridBagConstraints) gbcLabel.clone();
+        gbc_jlEmpty.gridy = 18;
+        gbc_jlEmpty.gridwidth = 2; //takes two columns
+        gbc_jlEmpty.ipady = 40;
+
+        JPanel jpCertificate = new JPanel(new GridBagLayout());
+        jpCertificate.setBorder(new CompoundBorder(
+            new EmptyBorder(15, 15, 15, 15), new EtchedBorder()));
+
+        if (intendedUses != null){
+        	jpCertificate.add(jpUses, gbc_jpUses);
+        }
+        jpCertificate.add(jlIssuedTo, gbc_jlIssuedTo); // Issued To
+        jpCertificate.add(jlCN, gbc_jlCN);
+        jpCertificate.add(jlCNValue, gbc_jlCNValue);
+        jpCertificate.add(jlOrg, gbc_jlOrg);
+        jpCertificate.add(jlOrgValue, gbc_jlOrgValue);        
+        jpCertificate.add(jlOU, gbc_jlOU);
+        jpCertificate.add(jlOUValue, gbc_jlOUValue);
+        //jpCertificate.add(jlEmail, gbc_jlEmail);
+        //jpCertificate.add(jlEmailValue, gbc_jlEmailValue);
+        jpCertificate.add(jlSN, gbc_jlSN);
+        jpCertificate.add(jlSNValue, gbc_jlSNValue);
+        jpCertificate.add(jlVersion, gbc_jlVersion);
+        jpCertificate.add(jlVersionValue, gbc_jlVersionValue);
+        jpCertificate.add(jlIssuedBy, gbc_jlIssuedBy); //Issued By
+        jpCertificate.add(jlICN, gbc_jlICN);
+        jpCertificate.add(jlICNValue, gbc_jlICNValue);
+        jpCertificate.add(jlIOrg, gbc_jlIOrg);
+        jpCertificate.add(jlIOrgValue, gbc_jlIOrgValue);        
+        jpCertificate.add(jlIOU, gbc_jlIOU);
+        jpCertificate.add(jlIOUValue, gbc_jlIOUValue);
+        jpCertificate.add(jlValidity, gbc_jlValidity); //Validity
+        jpCertificate.add(jlIssuedOn, gbc_jlIssuedOn);
+        jpCertificate.add(jlIssuedOnValue, gbc_jlIssuedOnValue);
+        jpCertificate.add(jlExpiresOn, gbc_jlExpiresOn);
+        jpCertificate.add(jlExpiresOnValue, gbc_jlExpiresOnValue); 
+        jpCertificate.add(jlFingerprints, gbc_jlFingerprints); //Fingerprints
+        jpCertificate.add(jlSHA1Fingerprint, gbc_jlSHA1Fingerprint);
+        jpCertificate.add(jlSHA1FingerprintValue, gbc_jlSHA1FingerprintValue);
+        jpCertificate.add(jlMD5Fingerprint, gbc_jlMD5Fingerprint);
+        jpCertificate.add(jlMD5FingerprintValue, gbc_jlMD5FingerprintValue);
+        jpCertificate.add(jlEmpty, gbc_jlEmpty); //Empty label to get some vertical space on the frame
+
+        // List of serviceURLs
+        JPanel jpURLs  = null; // Panel to hold the URL list
+        if (serviceURLs!=null){ //if service serviceURLs are not null (even if empty - show empty list)
+
+        	jpURLs = new JPanel(new BorderLayout());
+        	jpURLs.setBorder(new CompoundBorder(
+                    new EmptyBorder(0, 15, 0, 15), new EtchedBorder()));
+            // Label
+            JLabel jlServiceURLs = new JLabel ("Service URLs this key pair will be used for:");
+            jlServiceURLs.setFont(new Font(null, Font.BOLD, 11));
+            jlServiceURLs.setBorder(new EmptyBorder(5,5,5,5));    
+      
+            // New empty service serviceURLs list
+            DefaultListModel jltModel = new DefaultListModel();
+            JList jltServiceURLs = new JList(jltModel); 
+            for (String url : serviceURLs){
+            	jltModel.addElement(url);
+            }
+            jltServiceURLs.setVisibleRowCount(5); //don't show more than 5 otherwise the window is too big
+            
+            // Scroll pane for service serviceURLs
+            JScrollPane jspServiceURLs = new JScrollPane(jltServiceURLs,
+                    JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+                    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+            jspServiceURLs.getViewport().setBackground(jltServiceURLs.getBackground());
+
+            jpURLs.add(jlServiceURLs, BorderLayout.NORTH);
+            jpURLs.add(jspServiceURLs, BorderLayout.CENTER);
+            
+            // Put it on the main content pane
+            getContentPane().add(jpURLs, BorderLayout.CENTER);
+        }
+        
+        // OK button
+        JPanel jpOK = new JPanel(new FlowLayout(FlowLayout.CENTER));
+
+        final JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+                okPressed();
+            }
+        });
+
+        jpOK.add(jbOK);
+         
+        // Put it all together (panel with URL list is already added, if it was not null)
+        getContentPane().add(jpCertificate, BorderLayout.NORTH);
+        getContentPane().add(jpOK, BorderLayout.SOUTH);
+
+        // Resizing wreaks havoc
+        setResizable(false);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+
+        SwingUtilities.invokeLater(new Runnable()
+        {
+            public void run()
+            {
+                jbOK.requestFocus();
+            }
+        });
+    }
+    
+    /**
+     * Get the digest of a message as a formatted String.
+     *
+     * @param bMessage The message to digest
+     * @param digestType The message digest algorithm
+     * @return The message digest
+     * @throws CMException If there was a problem generating the message
+     * digest
+     */
+    public static String getMessageDigest(byte[] bMessage,
+        String digestType)
+        throws CMException
+    {
+        // Create message digest object using the supplied algorithm
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance(digestType);
+        }
+        catch (NoSuchAlgorithmException ex) {
+            throw new CMException("Failed to create message digest.", ex);
+        }
+
+        // Create raw message digest
+        byte[] bFingerPrint = messageDigest.digest(bMessage);
+
+        // Place the raw message digest into a StringBuffer as a Hex number
+        StringBuffer strBuff = new StringBuffer(
+            new BigInteger(1, bFingerPrint).toString(16).toUpperCase());
+
+        // Odd number of characters so add in a padding "0"
+        if ((strBuff.length() % 2) != 0) {
+            strBuff.insert(0, '0');
+        }
+
+        // Place colons at every two hex characters
+        if (strBuff.length() > 2) {
+            for (int iCnt = 2; iCnt < strBuff.length(); iCnt += 3) {
+                strBuff.insert(iCnt, ':');
+            }
+        }
+
+        // Return the formatted message digest
+        return strBuff.toString();
+    }
+    
+    /**
+     * Gets the intended certificate uses, i.e. Netscape Certificate Type extension (2.16.840.1.113730.1.1) 
+     * value as a string
+     * @param value Extension value as a DER-encoded OCTET string
+     * @return Extension value as a string
+     */
+    private String getIntendedUses(byte[] value)
+    {
+    	
+        // Netscape Certificate Types (2.16.840.1.113730.1.1)
+        int[] INTENDED_USES = new int[] {
+            NetscapeCertType.sslClient,
+            NetscapeCertType.sslServer,
+            NetscapeCertType.smime,
+            NetscapeCertType.objectSigning,
+            NetscapeCertType.reserved,
+            NetscapeCertType.sslCA,
+            NetscapeCertType.smimeCA,
+            NetscapeCertType.objectSigningCA,
+        };
+        
+        // Netscape Certificate Type strings (2.16.840.1.113730.1.1)
+        HashMap<String, String> INTENDED_USES_STRINGS = new HashMap<String, String> ();
+        INTENDED_USES_STRINGS.put("128", "SSL Client");
+        INTENDED_USES_STRINGS.put("64", "SSL Server");
+        INTENDED_USES_STRINGS.put("32", "S/MIME");
+        INTENDED_USES_STRINGS.put("16", "Object Signing");
+        INTENDED_USES_STRINGS.put("8", "Reserved");
+        INTENDED_USES_STRINGS.put("4", "SSL CA");
+        INTENDED_USES_STRINGS.put("2", "S/MIME CA");
+        INTENDED_USES_STRINGS.put("1", "Object Signing CA");
+        
+        
+        // Get octet string from extension value
+        ASN1OctetString fromByteArray = new DEROctetString(value);
+		byte[] octets = fromByteArray.getOctets();            
+    	DERBitString fromByteArray2 = new DERBitString(octets);
+		int val = new NetscapeCertType(fromByteArray2).intValue();
+        StringBuffer strBuff = new StringBuffer();
+        for (int i = 0, len = INTENDED_USES.length; i < len; i++) {
+            int use = INTENDED_USES[i];
+            if ((val & use) == use) {
+                strBuff.append(INTENDED_USES_STRINGS.get(String.valueOf(use))+", \n");
+            }
+        }
+        // remove the last ", \n" from the end of the buffer
+        String str = strBuff.toString();
+        str = str.substring(0, str.length()-3);
+        return str;
+    }
+    
+    /**
+     * OK button pressed.
+     */
+    private void okPressed()
+    {
+        closeDialog();
+    }
+
+    /**
+     * Closes the View Certificate Entry dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewPasswordDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewPasswordDialog.java
new file mode 100644
index 0000000..7158486
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewPasswordDialog.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+
+/**
+ * Dialog used for viewing password.
+ * 
+ * @author Alexandra Nenadic
+ */
+@SuppressWarnings("serial")
+public class ViewPasswordDialog extends JDialog {
+	
+	// Password field 
+    private JTextField jtfPassword;
+    
+    // Password value
+    private String sPassword;
+
+   /**
+     * Creates new ViewPasswordDialog dialog where the parent is a frame.
+     */
+    public ViewPasswordDialog(JFrame parent, boolean bModal, String password)
+    {
+        this(parent, "View password", bModal, password);
+    }
+
+    /**
+     * Creates new ViewPasswordDialog dialog where the parent is a frame.
+     *
+     * @param parent Parent frame
+     * @param sTitle The dialog's title
+     * @param bModal Is dialog modal?
+     * @param password Password value
+     */
+    public ViewPasswordDialog(JFrame parent, String sTitle, boolean bModal, String password)
+    {
+        super(parent, sTitle, bModal);  
+        sPassword = password;
+        initComponents();
+    }
+
+    /**
+     * Creates new ViewPasswordDialog dialog where the parent is a dialog.
+     */
+    public ViewPasswordDialog(JDialog parent, boolean bModal, String password)
+    {
+        this(parent, "View password", bModal, password);
+    }
+
+    /**
+     * Creates new ViewPasswordDialog dialog where the parent is a dialog.
+     */
+    public ViewPasswordDialog(JDialog parent, String sTitle, boolean bModal, String password)
+    {
+        super(parent, sTitle, bModal);
+        sPassword = password;
+        initComponents();
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+
+        JLabel jlPassword = new JLabel("Password value");
+
+        //Populate the password field
+        jtfPassword = new JTextField(15);
+        jtfPassword.setText(sPassword);
+        jtfPassword.setEditable(false);
+        
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+            	closeDialog();
+            }
+        });
+        
+        JPanel jpPassword = new JPanel(new BorderLayout());
+        jpPassword.add(jlPassword, BorderLayout.NORTH);
+        jpPassword.add(jtfPassword, BorderLayout.CENTER);
+        //jpPassword.setBorder(new EmptyBorder(5, 5, 5, 5));
+        jpPassword.setBorder(new CompoundBorder(
+                new EmptyBorder(5, 5, 5, 5), new EtchedBorder()));
+        
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+        
+        getContentPane().add(jpPassword, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
+
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewUsernamePasswordEntryDialog.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewUsernamePasswordEntryDialog.java
new file mode 100644
index 0000000..00e92fe
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/ViewUsernamePasswordEntryDialog.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * 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 java.awt.BorderLayout;
+import java.awt.FlowLayout;
+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.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+
+/**
+ * Dialog used for viewing service URL, username and password.
+ * 
+ * @author Alex Nenadic
+ */
+public class ViewUsernamePasswordEntryDialog
+    extends JDialog
+{
+	private static final long serialVersionUID = -7224904997349644853L;
+
+	// Service URL field 
+    private JTextField jtfServiceURL;
+    
+    // Username field 
+    private JTextField jtfUsername;
+    
+    // Password field 
+    private JTextField jtfPassword;
+
+    // Service URL value
+    private String serviceURL;    
+    
+    // Service username value
+    private String username;
+    
+    // Service password value
+    private String password;
+
+    /**
+     * Creates new ViewPasswordEntryDialog dialog where the parent is a frame.
+     */
+    public ViewUsernamePasswordEntryDialog(JFrame parent, String currentURL, String currentUsername, String currentPassword)
+    {
+        super(parent, "View username and password for a service", true);
+        serviceURL = currentURL;
+        username = currentUsername;
+        password = currentPassword;
+        initComponents();
+    }
+
+    /**
+     * Creates new ViewPasswordDialog dialog where the parent is a dialog.
+     */
+    public ViewUsernamePasswordEntryDialog(JDialog parent, String currentURL, String currentUsername, String currentPassword)
+    {
+        super(parent, "View username and password for a service", true);
+        serviceURL = currentURL;
+        username = currentUsername;
+        password = currentPassword;
+        initComponents();
+    }
+
+    /**
+     * Initialise the dialog's GUI components.
+     */
+    private void initComponents()
+    {
+        getContentPane().setLayout(new BorderLayout());
+
+        JLabel jlServiceURL = new JLabel("Service URL");
+        jlServiceURL.setBorder(new EmptyBorder(0,5,0,0));
+        JLabel jlUsername = new JLabel("Username");
+        jlUsername.setBorder(new EmptyBorder(0,5,0,0));
+        JLabel jlPassword = new JLabel("Password");
+        jlPassword.setBorder(new EmptyBorder(0,5,0,0));
+
+        //Populate the fields with values and disable user input
+        jtfServiceURL = new JTextField(15);
+        jtfServiceURL.setText(serviceURL);
+        jtfServiceURL.setEditable(false);
+        //jtfServiceURL.setBorder(new EmptyBorder(0,0,0,5));
+        
+        jtfUsername = new JTextField(15);
+        jtfUsername.setText(username);
+        jtfUsername.setEditable(false);
+       // jtfUsername.setBorder(new EmptyBorder(0,0,0,5));
+        
+        jtfPassword = new JTextField(15);
+        jtfPassword.setText(password);
+        jtfPassword.setEditable(false);
+        //jtfPassword.setBorder(new EmptyBorder(0,0,0,5));
+
+        JButton jbOK = new JButton("OK");
+        jbOK.addActionListener(new ActionListener()
+        {
+            public void actionPerformed(ActionEvent evt)
+            {
+            	closeDialog();
+            }
+        });
+        
+//        JButton jbViewPassword = new JButton("View password");
+//        jbViewPassword.addActionListener(new ActionListener()
+//        {
+//            public void actionPerformed(ActionEvent evt)
+//            {
+//            	showPassword();
+//            }
+//        });
+        
+        JPanel jpPassword = new JPanel(new GridLayout(4, 2, 5, 5));
+        jpPassword.add(jlServiceURL);
+        jpPassword.add(jtfServiceURL);
+        jpPassword.add(jlUsername);
+        jpPassword.add(jtfUsername);
+        jpPassword.add(jlPassword);
+        jpPassword.add(jtfPassword);
+        jpPassword.setBorder(new CompoundBorder(
+                new EmptyBorder(10, 10, 10, 10), new EtchedBorder()));
+        
+        JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        jpButtons.add(jbOK);
+       // jpButtons.add(jbViewPassword);
+        
+        getContentPane().add(jpPassword, BorderLayout.CENTER);
+        getContentPane().add(jpButtons, BorderLayout.SOUTH);
+
+        addWindowListener(new WindowAdapter()
+        {
+            public void windowClosing(WindowEvent evt)
+            {
+                closeDialog();
+            }
+        });
+
+        setResizable(false);
+
+        getRootPane().setDefaultButton(jbOK);
+
+        pack();
+    }
+
+    /**
+     * Close the dialog.
+     */
+    private void closeDialog()
+    {
+        setVisible(false);
+        dispose();
+    }
+}
+
+
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/action/CredentialManagerAction.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/action/CredentialManagerAction.java
new file mode 100644
index 0000000..b41d512
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/action/CredentialManagerAction.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.action;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+//import javax.swing.SwingUtilities;
+
+import net.sf.taverna.t2.workbench.ui.credentialmanager.CredentialManagerUI;
+
+@SuppressWarnings("serial")
+public class CredentialManagerAction extends AbstractAction {
+
+	private static ImageIcon ICON = new ImageIcon(CredentialManagerAction.class.getResource("/images/cred_manager16x16.png"));
+	
+	public CredentialManagerAction() {
+		super("Credential Manager",ICON);
+	}
+	
+	public void actionPerformed(ActionEvent e) {
+		CredentialManagerUI cmUI = CredentialManagerUI.getInstance();
+		cmUI.setVisible(true);
+
+//		Runnable createAndShowCredentialManagerUI = new Runnable(){
+//
+//		   public void run()
+//		   	{
+//			   CredentialManagerUI cmUI = new CredentialManagerUI();
+//   				cmUI.setVisible(true);
+//		   	}
+//		};
+//		SwingUtilities.invokeLater(createAndShowCredentialManagerUI);
+
+	}
+}
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/menu/CredentialManagerMenu.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/menu/CredentialManagerMenu.java
new file mode 100644
index 0000000..34a90af
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/menu/CredentialManagerMenu.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.menu;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.action.CredentialManagerAction;
+
+public class CredentialManagerMenu extends AbstractMenuAction{
+
+	private static Logger logger = Logger.getLogger(CredentialManagerMenu.class);
+	
+	public CredentialManagerMenu() {
+		super(URI.create("http://taverna.sf.net/2008/t2workbench/menu#advanced"),60);
+		// Force initialisation at startup
+		
+		try {
+			CredentialManager.initialiseSSL();
+		} catch (CMException e) {
+			logger.error("Could not initialise SSL", e);
+		}
+	}
+
+	@Override
+	protected Action createAction() {
+		return new CredentialManagerAction();
+	}
+
+}
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/toolbar/CredentialManagerToolbarAction.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/toolbar/CredentialManagerToolbarAction.java
new file mode 100644
index 0000000..dd97337
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/toolbar/CredentialManagerToolbarAction.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.toolbar;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.ui.credentialmanager.action.CredentialManagerAction;
+
+public class CredentialManagerToolbarAction extends AbstractMenuAction{
+
+	public CredentialManagerToolbarAction() {
+		super(CredentialManagerToolbarSection.CREDENTIAL_MANAGER_TOOLBAR_SECTION,100,URI.create("http://taverna.sf.net/2008/t2workbench/toolbar#credentialManagerAction"));
+	}
+
+	@Override
+	protected Action createAction() {
+		return new CredentialManagerAction();
+	}
+
+}
diff --git a/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/toolbar/CredentialManagerToolbarSection.java b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/toolbar/CredentialManagerToolbarSection.java
new file mode 100644
index 0000000..9b1204f
--- /dev/null
+++ b/src/main/java/net/sf/taverna/t2/workbench/ui/credentialmanager/toolbar/CredentialManagerToolbarSection.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.toolbar;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
+import net.sf.taverna.t2.ui.menu.DefaultToolBar;
+
+public class CredentialManagerToolbarSection extends AbstractMenuSection {
+
+	public static URI CREDENTIAL_MANAGER_TOOLBAR_SECTION = URI.create("http://taverna.sf.net/2008/t2workbench/toolbar#credentialManagerSection");
+	
+	public CredentialManagerToolbarSection() {
+		super(DefaultToolBar.DEFAULT_TOOL_BAR, 100, CREDENTIAL_MANAGER_TOOLBAR_SECTION);
+	}
+
+}
diff --git a/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent b/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
new file mode 100644
index 0000000..3743c2f
--- /dev/null
+++ b/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
@@ -0,0 +1,3 @@
+net.sf.taverna.t2.workbench.ui.credentialmanager.menu.CredentialManagerMenu
+#net.sf.taverna.t2.workbench.ui.credentialmanager.toolbar.CredentialManagerToolbarAction
+#net.sf.taverna.t2.workbench.ui.credentialmanager.toolbar.CredentialManagerToolbarSection
\ No newline at end of file
diff --git a/src/main/resources/images/cred_manager.png b/src/main/resources/images/cred_manager.png
new file mode 100644
index 0000000..48cd63c
--- /dev/null
+++ b/src/main/resources/images/cred_manager.png
Binary files differ
diff --git a/src/main/resources/images/cred_manager16x16.png b/src/main/resources/images/cred_manager16x16.png
new file mode 100644
index 0000000..c6e73b5
--- /dev/null
+++ b/src/main/resources/images/cred_manager16x16.png
Binary files differ
diff --git a/src/main/resources/images/cred_manager_transparent.png b/src/main/resources/images/cred_manager_transparent.png
new file mode 100644
index 0000000..1e89bde
--- /dev/null
+++ b/src/main/resources/images/cred_manager_transparent.png
Binary files differ
diff --git a/src/main/resources/images/table/entry_heading.png b/src/main/resources/images/table/entry_heading.png
new file mode 100644
index 0000000..8b59845
--- /dev/null
+++ b/src/main/resources/images/table/entry_heading.png
Binary files differ
diff --git a/src/main/resources/images/table/key_entry.png b/src/main/resources/images/table/key_entry.png
new file mode 100644
index 0000000..1fd18c6
--- /dev/null
+++ b/src/main/resources/images/table/key_entry.png
Binary files differ
diff --git a/src/main/resources/images/table/keypair_entry.png b/src/main/resources/images/table/keypair_entry.png
new file mode 100644
index 0000000..8fd3e8b
--- /dev/null
+++ b/src/main/resources/images/table/keypair_entry.png
Binary files differ
diff --git a/src/main/resources/images/table/trustcert_entry.png b/src/main/resources/images/table/trustcert_entry.png
new file mode 100644
index 0000000..0f110e1
--- /dev/null
+++ b/src/main/resources/images/table/trustcert_entry.png
Binary files differ