bloritsch 01/09/05 05:21:46
Added: src/org/apache/jmeter/gui/action SSLManagerCommand.java
src/org/apache/jmeter/util SSLManager.java
Log:
Add SSL Manager code
Revision Changes Path
1.1
jakarta-jmeter/src/org/apache/jmeter/gui/action/SSLManagerCommand.java
Index: SSLManagerCommand.java
===================================================================
/*
* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache JMeter" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* "Apache JMeter", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jmeter.gui.action;
import java.awt.event.ActionEvent;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
import org.apache.jmeter.gui.GuiPackage;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.util.SSLManager;
import java.io.File;
import javax.swing.filechooser.FileFilter;
/**
* SSL Manager Command. The SSL Manager provides a mechanism to change your
* client authentication if required by the server. If you have JSSE 1.0.2
* installed, you can select your client identity from a list of installed keys.
* You can also change your keystore. JSSE 1.0.2 allows you to export a PKCS#12
* key from Netscape 4.04 or higher and use it in a read only format. You must
* supply a password that is greater than six characters due to limitations in
* the keytool program--and possibly the rest of the system.
*
* <p>
* By selecting a *.p12 file as your keystore (your PKCS#12) format file, you can
* have a whopping one key keystore. The advantage is that you can test a
* connection using the assigned Certificate from a Certificate Authority.
* </p>
*
* @author <a href="[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/09/05 12:21:46 $
*/
public class SSLManagerCommand implements Command {
private static Set commandSet;
private JFileChooser keyStoreChooser;
static {
HashSet commands = new HashSet();
commands.add("sslManager");
SSLManagerCommand.commandSet = Collections.unmodifiableSet(commands);
System.setProperty("java.protocol.handler.pkgs",
"com.sun.net.ssl.internal.www.protocol");
System.setProperty("javax.net.ssl.debug", "all");
}
/**
* Handle the "sslmanager" action by displaying the "SSL CLient Manager"
* dialog box. The Dialog Box is NOT modal, because those should be avoided
* if at all possible.
*/
public void doAction(ActionEvent e) {
if (e.getActionCommand().equals("sslManager")) {
this.sslManager();
}
}
/**
* Provide the list of Action names that are available in this command.
*/
public Set getActionNames() {
return SSLManagerCommand.commandSet;
}
/**
* Called by sslManager button. Raises sslManager dialog. Currently the
sslManager box has
* the product image and the copyright notice. The dialog box is centered
* over the MainFrame.
*/
private void sslManager() {
SSLManager.reset();
keyStoreChooser = new
JFileChooser(JMeterUtils.getJMeterProperties().getProperty("user.dir"));
keyStoreChooser.addChoosableFileFilter(new AcceptPKCS12FileFilter());
keyStoreChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int retVal =
keyStoreChooser.showOpenDialog(GuiPackage.getInstance().getMainFrame());
if (JFileChooser.APPROVE_OPTION == retVal) {
File selectedFile = keyStoreChooser.getSelectedFile();
try {
JMeterUtils.getJMeterProperties().setProperty("javax.net.ssl.keyStore",
selectedFile.getCanonicalPath());
} catch (Exception e) {
}
}
keyStoreChooser = null;
SSLManager.getInstance();
}
/**
* Internal class to add a PKCS12 file format filter for JFileChooser.
*/
static private class AcceptPKCS12FileFilter extends FileFilter {
/**
* Get the description that shows up in JFileChooser filter menu.
*
* @return description
*/
public String getDescription() {
return "PKCS 12 Key (*.p12)";
}
/**
* Tests to see if the file ends with "*.p12" or "*.P12".
*
* @param testfile file to test
* @return true if file is accepted, false otherwise
*/
public boolean accept(File testFile) {
return testFile.isDirectory() ||
testFile.getName().endsWith(".p12") ||
testFile.getName().endsWith(".P12");
}
}
}
1.1 jakarta-jmeter/src/org/apache/jmeter/util/SSLManager.java
Index: SSLManager.java
===================================================================
/*
* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache JMeter" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* "Apache JMeter", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jmeter.util;
import java.io.File;
import java.io.FileInputStream;
import java.security.Principal;
import java.security.SecureRandom;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.PrivateKey;
import java.security.Key;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JOptionPane;
import com.sun.net.ssl.SSLContext;
import com.sun.net.ssl.X509KeyManager;
import com.sun.net.ssl.KeyManager;
import com.sun.net.ssl.KeyManagerFactory;
import com.sun.net.ssl.HttpsURLConnection;
import org.apache.jmeter.gui.GuiPackage;
/**
* The SSLManager handles the KeyStore information for JMeter. Basically, it
* handles all the logic for loading and initializing all the JSSE parameters
* and selecting the alias to authenticate against if it is available. SSLManager
* will try to automatically select the client certificate for you, but if it can't
* make a decision, it will pop open a dialog asking you for more information.
*
* @author <a href="[EMAIL PROTECTED]">Berin Loritsch</a>
* @version CVS $Revision: 1.1 $ $Date: 2001/09/05 12:21:46 $
*/
public class SSLManager {
/** Singleton instance of the manager */
private static SSLManager manager;
/** Cache the SecureRandom instance because it takes a long time to create */
private static SecureRandom rand;
/** Cache the KeyStore instance */
private KeyStore keyStore;
/** Have the password available */
private String defaultpw =
JMeterUtils.getJMeterProperties().getProperty("javax.net.ssl.keyStorePassword");
/** Cache the Context so we can retrieve it from other places */
private SSLContext context = null;
/**
* Resets the SSLManager so that we can create a new one with a new keystore
*/
static public void reset() {
SSLManager.manager = null;
}
/**
* Returns the SSLContext we are using. It is useful for obtaining the
SSLSocketFactory
* so that your created sockets are authenticated.
*/
public SSLContext getContext() {
return this.context;
}
/**
* Opens and initializes the KeyStore. If the password for the KeyStore is
* not set, this method will prompt you to enter it. Unfortunately, there is
* no PasswordEntryField available from JOptionPane.
*/
private KeyStore getKeyStore() {
String password = this.defaultpw;
if (null == this.keyStore) {
String defaultName =
JMeterUtils.getJMeterProperties().getProperty("user.home") + File.separator +
".keystore";
String fileName =
JMeterUtils.getJMeterProperties().getProperty("javax.net.ssl.keyStore", defaultName);
System.setProperty("javax.net.ssl.keyStore", fileName);
try {
if (fileName.endsWith(".p12") || fileName.endsWith(".P12")) {
this.keyStore = KeyStore.getInstance("pkcs12");
System.out.println("KeyStore Type: PKCS 12");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
} else {
this.keyStore = KeyStore.getInstance("JKS");
System.out.println("KeyStore Type: JKS");
}
} catch (KeyStoreException e) {
JOptionPane.showMessageDialog(GuiPackage.getInstance().getMainFrame(),
e,
"KeyStore Problem",
JOptionPane.ERROR_MESSAGE);
this.keyStore = null;
throw new RuntimeException("KeyStore Problem");
}
if (null == password) {
if (null == defaultpw) {
this.defaultpw =
JMeterUtils.getJMeterProperties().getProperty("javax.net.ssl.keyStorePassword");
if (null == defaultpw) {
synchronized(this) {
this.defaultpw =
JOptionPane.showInputDialog(GuiPackage.getInstance().getMainFrame(),
"KeyStore Password",
"Input Password",
JOptionPane.QUESTION_MESSAGE);
JMeterUtils.getJMeterProperties().setProperty("javax.net.ssl.keyStorePassword",
this.defaultpw);
}
}
}
password = this.defaultpw;
System.setProperty("javax.net.ssl.keyStorePassword", password);
}
try {
File initStore = new File(fileName);
if (initStore.exists()) {
try {
this.keyStore.load(new FileInputStream(initStore),
password.toCharArray());
} catch (Exception e) {
throw new RuntimeException("Can't load KeyStore!!! " +
e.getMessage());
}
} else {
this.keyStore.load(null, password.toCharArray());
}
} catch (Exception e) {
}
}
return this.keyStore;
}
/**
* Private Constructor to remove the possibility of directly instantiating
* this object. Create the SSLContext, and wrap all the X509KeyManagers with
* our X509KeyManager so that we can choose our alias.
*/
private SSLManager() {
if (null == this.rand) {
this.rand = new SecureRandom();
}
try {
this.context = SSLContext.getInstance("TLS");
KeyManagerFactory managerFactory =
KeyManagerFactory.getInstance("SunX509");
KeyStore keys = this.getKeyStore();
managerFactory.init(keys, this.defaultpw.toCharArray());
KeyManager[] managers = managerFactory.getKeyManagers();
for (int i = 0; i < managers.length; i++) {
if (managers[i] instanceof X509KeyManager) {
X509KeyManager manager = (X509KeyManager) managers[i];
managers[i] = new WrappedX509KeyManager(manager, keys,
this.defaultpw);
}
}
context.init(managers, null, this.rand);
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (Exception e) {
}
}
/**
* Static accessor for the SSLManager object. The SSLManager is a singleton.
*/
public static final SSLManager getInstance() {
if (null == SSLManager.manager) {
SSLManager.manager = new SSLManager();
}
return SSLManager.manager;
}
/**
* This is the X509KeyManager we have defined for the sole purpose of selecing
* the proper key and certificate based on the keystore available.
*/
private static class WrappedX509KeyManager implements X509KeyManager {
/** The parent X509KeyManager */
private final X509KeyManager manager;
/** The default password passed from the instantiator */
private String defaultpw =
JMeterUtils.getJMeterProperties().getProperty("javax.net.ssl.keyStorePassword");
/** The default alias discovered automatically or from user input */
private String defaultAlias =
JMeterUtils.getJMeterProperties().getProperty("jmeter.ssl.default.alias");
/** The KeyStore this KeyManager uses */
private final KeyStore store;
/**
* Instantiate a new WrappedX509KeyManager.
*
* @param parent The parent X509KeyManager
* @param ks The KeyStore we derive our client certs and keys from
* @param password The password used for the KeyStore and the private key.
*/
public WrappedX509KeyManager(X509KeyManager parent, KeyStore ks, String
password) {
if (null != password) {
this.defaultpw = password;
}
this.manager = parent;
this.store = ks;
}
/**
* Select the Alias we will authenticate as if Client authentication is
* required by the server we are connecting to. We get the list of aliases,
* and if there is only one alias we automatically select it. If there are
* more than one alias that has a private key, we prompt the user to choose
* which alias using a combo box. Otherwise, we simply provide a text box,
* which may or may not work. The alias does have to match one in the
keystore.
*
* @param keyType The type of private key the server expects (RSA, DSA,
etc.)
* @param issuers The CA certificates we are narrowing our selection on.
*/
public String chooseClientAlias(String keyType, Principal[] issuers) {
if (null == this.defaultAlias) {
String[] aliases = this.getClientAliases(keyType, issuers);
if (null != aliases && aliases.length == 1) {
this.defaultAlias = aliases[0];
} else if (aliases.length > 1) {
synchronized(this) {
this.defaultAlias = (String)
JOptionPane.showInputDialog(GuiPackage.getInstance().getMainFrame(),
"Select Your Alias for the test",
"Client Alias",
JOptionPane.QUESTION_MESSAGE,
null,
aliases,
aliases[0]);
}
} else {
synchronized(this) {
this.defaultAlias =
JOptionPane.showInputDialog(GuiPackage.getInstance().getMainFrame(),
"Please type your prefered
alias",
"Client Alias",
JOptionPane.QUESTION_MESSAGE);
}
}
}
System.out.println("Alias: " + this.defaultAlias);
return this.defaultAlias;
}
/**
* Compiles the list of all client aliases with a private key. Currently,
* keyType and issuers are both ignored.
*
* @param keyType The type of private key the server expects (RSA, DSA,
etc.)
* @param issuers The CA certificates we are narrowing our selection on.
*/
public String[] getClientAliases(String keyType, Principal[] issuers) {
List aliasList = new ArrayList();
try {
Enumeration aliases = this.store.aliases();
while (aliases.hasMoreElements()) {
String alias = (String) aliases.nextElement();
if (this.store.isKeyEntry(alias)) {
aliasList.add(alias);
}
}
} catch (Exception e) {
}
return (String[]) aliasList.toArray(new String[] {});
}
/**
* Choose the server alias for the SSLServerSockets. This are not used
* in JMeter.
*
* @param keyType The type of private key the server expects (RSA, DSA,
etc.)
* @param issuers The CA certificates we are narrowing our selection on.
*/
public String chooseServerAlias(String keyType, Principal[] issuers) {
return this.manager.chooseServerAlias(keyType, issuers);
}
/**
* Get the list of server aliases for the SSLServerSockets. This is not
* used in JMeter.
*
* @param keyType The type of private key the server expects (RSA, DSA,
etc.)
* @param issuers The CA certificates we are narrowing our selection on.
*/
public String[] getServerAliases(String keyType, Principal[] issuers) {
return this.manager.getServerAliases(keyType, issuers);
}
/**
* Get the Certificate chain for a particular alias
*
* @param alias The client alias
*/
public X509Certificate[] getCertificateChain(String alias) {
Certificate[] certs;
try {
certs = this.store.getCertificateChain(alias);
} catch (Exception e) {
return null;
}
X509Certificate[] x509certs = new X509Certificate[certs.length];
for (int i = 0; i < certs.length; i++) {
x509certs[i] = (X509Certificate)certs[i];
}
return x509certs;
}
/**
* Get the Private Key for a particular alias
*
* @param alias The client alias
*/
public PrivateKey getPrivateKey(String alias) {
try {
return (PrivateKey) this.store.getKey(alias,
this.defaultpw.toCharArray());
} catch (Exception e) {
}
return null;
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]